C++
C++语言
现代C++设计新思维
第一篇 技术(Techniques)
第1章 基于Policy的Class设计(Policy-Based Class Design)
第2章 技术(Techniques)
第3章 Typelists
第4章 小型对象分配技术(Small-Object Allocation)
第二篇 组件(Component)
第5章 泛化仿函数(Generalized Functions)
第6章 Singletons(单件)实作技术
第7章 Smart Pointers(智能指针)
第8章 Object Factiories(对象工厂)
第9章 Abstract Factory(抽象工厂)
第10章 Visitor(访问者,视察者)
第11章 Multimethods
附录 一个超迷你的多线程程序库(A Minimalist Multithreading Library)
C++源码摘要
// This is a source version of the cpp cheatsheet available here. Note that this does not compile but may have better
// color-highlight than the markdown version in an editor.
//
// Github version available here: https://github.com/mortennobel/cpp-cheatsheet
// # C++ QUICK REFERENCE / C++ CHEATSHEET
// Based on <a href="http://www.pa.msu.edu/~duxbury/courses/phy480/Cpp_refcard.pdf">Phillip M. Duxbury's C++ Cheatsheet</a> and edited by Morten Nobel-Jørgensen.
// The cheatsheet focus is both on the language as well as common classes from the standard library.
// C++11 additions is inspired by <a href="https://isocpp.org/blog/2012/12/c11-a-cheat-sheet-alex-sinyakov">ISOCPP.org C++11 Cheatsheet</a>).
//
// The goal is to give a concise overview of basic, modern C++ (C++14).
//
// The document is hosted on https://github.com/mortennobel/cpp-cheatsheet. Any comments and feedback are appreciated.
// ## Preprocessor
// Comment to end of line
/* Multi-line comment */
#include <stdio.h> // Insert standard header file
#include "myfile.h" // Insert file in current directory
#define X some text // Replace X with some text
#define F(a,b) a+b // Replace F(1,2) with 1+2
#define X \
some text // Multiline definition
#undef X // Remove definition
#if defined(X) // Conditional compilation (#ifdef X)
#else // Optional (#ifndef X or #if !defined(X))
#endif // Required after #if, #ifdef
// ## Literals
255, 0377, 0xff // Integers (decimal, octal, hex)
2147483647L, 0x7fffffffl // Long (32-bit) integers
123.0, 1.23e2 // double (real) numbers
'a', '\141', '\x61' // Character (literal, octal, hex)
'\n', '\\', '\'', '\"' // Newline, backslash, single quote, double quote
"string\n" // Array of characters ending with newline and \0
"hello" "world" // Concatenated strings
true, false // bool constants 1 and 0
nullptr // Pointer type with the address of 0
// ## Declarations
int x; // Declare x to be an integer (value undefined)
int x=255; // Declare and initialize x to 255
short s; long l; // Usually 16 or 32 bit integer (int may be either)
char c='a'; // Usually 8 bit character
unsigned char u=255;
signed char s=-1; // char might be either
unsigned long x =
0xffffffffL; // short, int, long are signed
float f; double d; // Single or double precision real (never unsigned)
bool b=true; // true or false, may also use int (1 or 0)
int a, b, c; // Multiple declarations
int a[10]; // Array of 10 ints (a[0] through a[9])
int a[]={0,1,2}; // Initialized array (or a[3]={0,1,2}; )
int a[2][2]={{1,2},{4,5}}; // Array of array of ints
char s[]="hello"; // String (6 elements including '\0')
std::string s = "Hello" // Creates string object with value "Hello"
std::string s = R"(Hello
World)"; // Creates string object with value "Hello\nWorld"
int* p; // p is a pointer to (address of) int
char* s="hello"; // s points to unnamed array containing "hello"
void* p=nullptr; // Address of untyped memory (nullptr is 0)
int& r=x; // r is a reference to (alias of) int x
enum weekend {SAT,SUN}; // weekend is a type with values SAT and SUN
enum weekend day; // day is a variable of type weekend
enum weekend{SAT=0,SUN=1}; // Explicit representation as int
enum {SAT,SUN} day; // Anonymous enum
enum class Color {Red,Blue};// Color is a strict type with values Red and Blue
= Color::Red; // Assign Color x to red
Color x typedef String char*; // String s; means char* s;
const int c=3; // Constants must be initialized, cannot assign to
const int* p=a; // Contents of p (elements of a) are constant
int* const p=a; // p (but not contents) are constant
const int* const p=a; // Both p and its contents are constant
const int& cr=x; // cr cannot be assigned to change x
int8_t,uint8_t,int16_t,
uint16_t,int32_t,uint32_t,
int64_t,uint64_t // Fixed length standard types
auto it = m.begin(); // Declares it to the result of m.begin()
auto const param = config["param"];
// Declares it to the const result
auto& s = singleton::instance();
// Declares it to a reference of the result
// ## STORAGE Classes
int x; // Auto (memory exists only while in scope)
static int x; // Global lifetime even if local scope
extern int x; // Information only, declared elsewhere
// ## Statements
=y; // Every expression is a statement
xint x; // Declarations are statements
; // Empty statement
{ // A block is a single statement
int x; // Scope of x is from declaration to end of block
}
if (x) a; // If x is true (not 0), evaluate a
else if (y) b; // If not x and y (optional, may be repeated)
else c; // If not x and not y (optional)
while (x) a; // Repeat 0 or more times while x is true
for (x; y; z) a; // Equivalent to: x; while(y) {a; z;}
for (x : y) a; // Range-based for loop e.g.
// for (auto& x in someList) x.y();
do a; while (x); // Equivalent to: a; while(x) a;
switch (x) { // x must be int
case X1: a; // If x == X1 (must be a const), jump here
case X2: b; // Else if x == X2, jump here
default: c; // Else jump here (optional)
}
break; // Jump out of while, do, or for loop, or switch
continue; // Jump to bottom of while, do, or for loop
return x; // Return x from function to caller
try { a; }
catch (T t) { b; } // If a throws a T, then jump here
catch (...) { c; } // If a throws something else, jump here
// ## Functions
int f(int x, int y); // f is a function taking 2 ints and returning int
void f(); // f is a procedure taking no arguments
void f(int a=0); // f() is equivalent to f(0)
(); // Default return type is int
finline f(); // Optimize for speed
() { statements; } // Function definition (must be global)
foperator+(T x, T y); // a+b (if type T) calls operator+(a, b)
T operator-(T x); // -a calls function operator-(a)
T operator++(int); // postfix ++ or -- (parameter ignored)
T extern "C" {void f();} // f() was compiled in C
// Function parameters and return values may be of any type. A function must either be declared or defined before
// it is used. It may be declared first and defined later. Every program consists of a set of a set of global variable
// declarations and a set of function definitions (possibly in separate files), one of which must be:
int main() { statements... } // or
int main(int argc, char* argv[]) { statements... }
// `argv` is an array of `argc` strings from the command line.
// By convention, `main` returns status `0` if successful, `1` or higher for errors.
//
// Functions with different parameters may have the same name (overloading). Operators except `::` `.` `.*` `?:` may be overloaded.
// Precedence order is not affected. New operators may not be created.
// ## Expressions
// Operators are grouped by precedence, highest first. Unary operators and assignment evaluate right to left. All
// others are left to right. Precedence does not affect order of evaluation, which is undefined. There are no run time
// checks for arrays out of bounds, invalid pointers, etc.
::X // Name X defined in class T
T::X // Name X defined in namespace N
N::X // Global name X
.x // Member x of struct or class t
t-> x // Member x of struct or class pointed to by p
p[i] // i'th element of array a
a(x,y) // Call to function f with arguments x and y
f(x,y) // Object of class T initialized with x and y
T++ // Add 1 to x, evaluates to original x (postfix)
x-- // Subtract 1 from x, evaluates to original x
xtypeid(x) // Type of x
typeid(T) // Equals typeid(x) if x is a T
dynamic_cast< T>(x) // Converts x to a T, checked at run time.
static_cast< T>(x) // Converts x to a T, not checked
reinterpret_cast< T>(x) // Interpret bits of x as a T
const_cast< T>(x) // Converts x to same type T but not const
sizeof x // Number of bytes used to represent object x
sizeof(T) // Number of bytes to represent type T
++x // Add 1 to x, evaluates to new value (prefix)
--x // Subtract 1 from x, evaluates to new value
~x // Bitwise complement of x
!x // true if x is 0, else false (1 or 0 in C)
-x // Unary minus
+x // Unary plus (default)
&x // Address of x
*p // Contents of address p (*&x equals x)
new T // Address of newly allocated T object
new T(x, y) // Address of a T initialized with x, y
new T[x] // Address of allocated n-element array of T
delete p // Destroy and free object at address p
delete[] p // Destroy and free array of objects at p
(T) x // Convert x to T (obsolete, use .._cast<T>(x))
* y // Multiply
x / y // Divide (integers round toward 0)
x % y // Modulo (result has sign of x)
x
+ y // Add, or \&x[y]
x - y // Subtract, or number of elements from *x to *y
x << y // x shifted y bits to left (x * pow(2, y))
x >> y // x shifted y bits to right (x / pow(2, y))
x
< y // Less than
x <= y // Less than or equal to
x > y // Greater than
x >= y // Greater than or equal to
x
& y // Bitwise and (3 & 6 is 2)
x ^ y // Bitwise exclusive or (3 ^ 6 is 5)
x | y // Bitwise or (3 | 6 is 7)
x && y // x and then y (evaluates y only if x (not 0))
x || y // x or else y (evaluates y only if x is false (0))
x = y // Assign y to x, returns new value of x
x += y // x = x + y, also -= *= /= <<= >>= &= |= ^=
x ? y : z // y if x is true (nonzero), else z
x throw x // Throw exception, aborts if not caught
, y // evaluates x and y, returns y (seldom used)
x
// ## Classes
class T { // A new type
private: // Section accessible only to T's member functions
protected: // Also accessible to classes derived from T
public: // Accessible to all
int x; // Member data
void f(); // Member function
void g() {return;} // Inline member function
void h() const; // Does not modify any data members
int operator+(int y); // t+y means t.operator+(y)
int operator-(); // -t means t.operator-()
(): x(1) {} // Constructor with initialization list
T(const T& t): x(t.x) {}// Copy constructor
T& operator=(const T& t)
T{x=t.x; return *this; } // Assignment operator
~T(); // Destructor (automatic cleanup routine)
explicit T(int a); // Allow t=T(3) but not t=3
(float x): T((int)x) {}// Delegate constructor to T(int)
Toperator int() const
{return x;} // Allows int(t)
friend void i(); // Global function i() has private access
friend class U; // Members of class U have private access
static int y; // Data shared by all T objects
static void l(); // Shared code. May access y but not x
class Z {}; // Nested class T::Z
typedef int V; // T::V means int
};
void T::f() { // Code for member function f of class T
this->x = x;} // this is address of self (means x=x;)
int T::y = 2; // Initialization of static member (required)
::l(); // Call to static member
T; // Create object t implicit call constructor
T t.f(); // Call method f on object t
t
struct T { // Equivalent to: class T { public:
virtual void i(); // May be overridden at run time by derived class
virtual void g()=0; }; // Must be overridden (pure virtual)
class U: public T { // Derived class U inherits all members of base T
public:
void g(int) override; }; // Override method g
class V: private T {}; // Inherited members of T become private
class W: public T, public U {};
// Multiple inheritance
class X: public virtual T {};
// Classes derived from X have base T directly
// All classes have a default copy constructor, assignment operator, and destructor, which perform the
// corresponding operations on each data member and each base class as shown above. There is also a default no-argument
// constructor (required to create arrays) if the class has no constructors. Constructors, assignment, and
// destructors do not inherit.
// ## Templates
template <class T> T f(T t);// Overload f for all types
template <class T> class X {// Class with type parameter T
(T t); }; // A constructor
Xtemplate <class T> X<T>::X(T t) {}
// Definition of constructor
<int> x(3); // An object of type "X of int"
Xtemplate <class T, class U=T, int n=0>
// Template with default parameters
// ## Namespaces
namespace N {class T {};} // Hide name T
::T t; // Use name T in namespace N
Nusing namespace N; // Make T visible without N::
// ## `memory` (dynamic memory management)
#include <memory> // Include memory (std namespace)
<int> x; // Empty shared_ptr to a integer on heap. Uses reference counting for cleaning up objects.
shared_ptr= make_shared<int>(12); // Allocate value 12 on heap
x <int> y = x; // Copy shared_ptr, implicit changes reference count to 2.
shared_ptr<< *y; // Dereference y to print '12'
cout if (y.get() == x.get()) { // Raw pointers (here x == y)
<< "Same";
cout }
.reset(); // Eliminate one owner of object
yif (y.get() != x.get()) {
<< "Different";
cout }
if (y == nullptr) { // Can compare against nullptr (here returns true)
<< "Empty";
cout }
= make_shared<int>(15); // Assign new value
y << *y; // Dereference x to print '15'
cout << *x; // Dereference x to print '12'
cout <int> w; // Create empty weak pointer
weak_ptr= y; // w has weak reference to y.
w if (shared_ptr<int> s = w.lock()) { // Has to be copied into a shared_ptr before usage
<< *s;
cout }
<int> z; // Create empty unique pointers
unique_ptr<int> q;
unique_ptr= make_unique<int>(16); // Allocate int (16) on heap. Only one reference allowed.
z = move(z); // Move reference from z to q.
q if (z == nullptr){
<< "Z null";
cout }
<< *q;
cout <B> r;
shared_ptr= dynamic_pointer_cast<B>(t); // Converts t to a shared_ptr<B>
r
// ## `math.h`, `cmath` (floating point math)
#include <cmath> // Include cmath (std namespace)
(x); cos(x); tan(x); // Trig functions, x (double) is in radians
sin(x); acos(x); atan(x); // Inverses
asin(y, x); // atan(y/x)
atan2(x); cosh(x); tanh(x); // Hyperbolic sin, cos, tan functions
sinh(x); log(x); log10(x); // e to the x, log base e, log base 10
exp(x, y); sqrt(x); // x to the y, square root
pow(x); floor(x); // Round up or down (as a double)
ceil(x); fmod(x, y); // Absolute value, x mod y
fabs
// ## `assert.h`, `cassert` (Debugging Aid)
#include <cassert> // Include iostream (std namespace)
assert(e); // If e is false, print message and abort
#define NDEBUG // (before #include <assert.h>), turn off assert
// ## `iostream.h`, `iostream` (Replaces `stdio.h`)
#include <iostream> // Include iostream (std namespace)
>> x >> y; // Read words x and y (any type) from stdin
cin << "x=" << 3 << endl; // Write line to stdout
cout << x << y << flush; // Write to stderr and flush
cerr = cin.get(); // c = getchar();
c .get(c); // Read char
cin.getline(s, n, '\n'); // Read line into char s[n] to '\n' (default)
cinif (cin) // Good state (not EOF)?
// To read/write any type T:
& operator>>(istream& i, T& x) {i >> ...; x=...; return i;}
istream& operator<<(ostream& o, const T& x) {return o << ...;}
ostream
// ## `fstream.h`, `fstream` (File I/O works like `cin`, `cout` as above)
#include <fstream> // Include filestream (std namespace)
("filename"); // Open text file for reading
ifstream f1if (f1) // Test if open and input available
>> x; // Read object from file
f1 .get(s); // Read char or line
f1.getline(s, n); // Read line into string s[n]
f1("filename"); // Open file for writing
ofstream f2if (f2) f2 << x; // Write to file
// ## `string` (Variable sized character array)
#include <string> // Include string (std namespace)
, s2="hello"; // Create strings
string s1.size(), s2.size(); // Number of characters: 0, 5
s1+= s2 + ' ' + "world"; // Concatenation
s1 == "hello world" // Comparison, also <, >, !=, etc.
s1 [0]; // 'h'
s1.substr(m, n); // Substring of size n starting at s1[m]
s1.c_str(); // Convert to const char*
s1= to_string(12.05); // Converts number to string
s1 (cin, s); // Read line ending in '\n'
getline
// ## `vector` (Variable sized array/stack with built in memory allocation)
#include <vector> // Include vector (std namespace)
<int> a(10); // a[0]..a[9] are int (default size is 0)
vector<int> b{1,2,3}; // Create vector with values 1,2,3
vector.size(); // Number of elements (10)
a.push_back(3); // Increase size to 11, a[10]=3
a.back()=4; // a[10]=4;
a.pop_back(); // Decrease size by 1
a.front(); // a[0];
a[20]=1; // Crash: not bounds checked
a.at(20)=1; // Like a[20] but throws out_of_range()
afor (int& p : a)
=0; // C++11: Set all elements of a to 0
pfor (vector<int>::iterator p=a.begin(); p!=a.end(); ++p)
*p=0; // C++03: Set all elements of a to 0
<int> b(a.begin(), a.end()); // b is copy of a
vector<T> c(n, x); // c[0]..c[n-1] init to x
vector[10]; vector<T> e(d, d+10); // e is initialized from d
T d
// ## `deque` (Array stack queue)
// `deque<T>` is like `vector<T>`, but also supports:
#include <deque> // Include deque (std namespace)
.push_front(x); // Puts x at a[0], shifts elements toward back
a.pop_front(); // Removes a[0], shifts toward front
a
// ## `utility` (pair)
#include <utility> // Include utility (std namespace)
<string, int> a("hello", 3); // A 2-element struct
pair.first; // "hello"
a.second; // 3
a
// ## `map` (associative array - usually implemented as binary search trees - avg. time complexity: O(log n))
#include <map> // Include map (std namespace)
<string, int> a; // Map from string to int
map["hello"] = 3; // Add or replace element a["hello"]
afor (auto& p:a)
<< p.first << p.second; // Prints hello, 3
cout .size(); // 1
a
// ## `unordered_map` (associative array - usually implemented as hash table - avg. time complexity: O(1))
#include <unordered_map> // Include map (std namespace)
<string, int> a; // Map from string to int
unordered_map["hello"] = 3; // Add or replace element a["hello"]
afor (auto& p:a)
<< p.first << p.second; // Prints hello, 3
cout .size(); // 1
a
// ## `set` (store unique elements - usually implemented as binary search trees - avg. time complexity: O(log n))
#include <set> // Include set (std namespace)
<int> s; // Set of integers
set.insert(123); // Add element to set
sif (s.find(123) != s.end()) // Search for an element
.erase(123);
s<< s.size(); // Number of elements in set
cout
// ## `unordered_set` (store unique elements - usually implemented as a hash set - avg. time complexity: O(1))
#include <unordered_set> // Include set (std namespace)
<int> s; // Set of integers
unordered_set.insert(123); // Add element to set
sif (s.find(123) != s.end()) // Search for an element
.erase(123);
s<< s.size(); // Number of elements in set
cout
// ## `algorithm` (A collection of 60 algorithms on sequences with iterators)
#include <algorithm> // Include algorithm (std namespace)
(x, y); max(x, y); // Smaller/larger of x, y (any type defining <)
min(x, y); // Exchange values of variables x and y
swap(a, a+n); // Sort array a[0]..a[n-1] by <
sort(a.begin(), a.end()); // Sort vector or deque
sort(a.begin(), a.end()); // Reverse vector or deque
reverse
// ## `chrono` (Time related library)
#include <chrono> // Include chrono
using namespace std::chrono; // Use namespace
auto from = // Get current time_point
::now();
high_resolution_clock// ... do some work
auto to = // Get current time_point
::now();
high_resolution_clockusing ms = // Define ms as floating point duration
<float, milliseconds::period>;
duration// Compute duration in milliseconds
<< duration_cast<ms>(to - from)
cout .count() << "ms";
// ## `thread` (Multi-threading library)
#include <thread> // Include thread
unsigned c =
(); // Hardware threads (or 0 for unknown)
hardware_concurrencyauto lambdaFn = [](){ // Lambda function used for thread body
<< "Hello multithreading";
cout };
(lambdaFn); // Create and run thread with lambda
thread t.join(); // Wait for t finishes
t
// --- shared resource example ---
; // Mutex for synchronization
mutex mut; // Shared condition variable
condition_variable condconst char* sharedMes // Shared resource
= nullptr;
auto pingPongFn = // thread body (lambda). Print someone else's message
[&](const char* mes){
while (true){
<mutex> lock(mut);// locks the mutex
unique_lockdo {
.wait(lock, [&](){ // wait for condition to be true (unlocks while waiting which allows other threads to modify)
condreturn sharedMes != mes; // statement for when to continue
});
} while (sharedMes == mes); // prevents spurious wakeup
<< sharedMes << endl;
cout = mes;
sharedMes .unlock(); // no need to have lock on notify
lock.notify_all(); // notify all condition has changed
cond}
};
= "ping";
sharedMes (pingPongFn, sharedMes); // start example with 3 concurrent threads
thread t1(pingPongFn, "pong");
thread t2(pingPongFn, "boing");
thread t3
// ## `future` (thread support library)
#include <future> // Include future
<int(int)> fib = // Create lambda function
function[&](int i){
if (i <= 1){
return 1;
}
return fib(i-1)
+ fib(i-2);
};
<int> fut = // result of async function
future(launch::async, fib, 4); // start async function in other thread
async// do some other work
<< fut.get(); // get result of async function. Wait if needed. cout
cpp_cheatsheet
INDEX
- Variable and fundamental data types
- Console Input/Output
- Generating Random Numbers
- Advanced Data Types
- Dynamic Memory Allocation
- Reference Variables
- For Each Loop
- Functions
- Object Oriented Programming
- Operator Overloading
- Object Relationship
- Inheritance
- Virtual Functions
- Templates
Variable and fundamental data types
Initializing a variable
- Copy initialization:
int numRings = 20;
- Direct initialization:
int numRings(20);
- Uniform initialization:
int numRings{20}
If uniform initialization is used with no value. Default is 0.
int numRings{}
Integers
Fixed width integers
Will give fixed sized integer in all architecture.
#include <cstdint> // for fixed width integers
/*
* 8 bit singed integer. Many systems consider them as chars. So it is better
* to not use them if using integers is the purpose
*/
int8_t var;
uint8_t var; // 8 bit unsigned integer
intN_t var; // N = 16, 32, 64 bits signed integer
uintN_t var; // N = 16, 32, 64 bits unsigned integer
Fixed width integers performance is machine dependent. To get the
fastest integer type on a specific machine use int_fastN_t
.
It will give the fastest integer which is at least N bits long. N = 8,
16, 32, 64.
int_fast32_t var;
To get the smallest integer which is at least N bits long use
int_leastN_t
where N = 8, 16, 32, 64.
int_least64_t var;
Floating point numbers
Setting precision of a floating point number:
#include <iostream>
#include <iomanip> // for std::setprecision()
int main(){
double d{12.34567890};
std::cout << "Without precision: " << d << std::endl;
std::cout << std::setprecision(4);
std::cout << "With precision: " << d << std::endl;
return 0;
}
Special floating numbers: positive infinity, negative infinity, not a number.
#include <iostream>
int main(){
float zero(0.0);
float posinf = 5.0 / zero;
float neginf = -5.0 / zero;
float nan = zero / zero;
std::cout << posinf << std::endl;
std::cout << neginf << std::endl;
std::cout << nan << std::endl;
return 0;
}
Boolean Numbers
#include <iostream>
int main(){
bool universeCameFromNothing(true);
std::cout << "Universe came from nothing: " << universeCameFromNothing
<< std::endl;
std::cout << std::boolalpha;
std::cout << "Universe came from nothing: " << universeCameFromNothing
<< std::endl;
return 0;
}
Type Casting
#include <iostream>
int main(){
char ch(65);
std::cout << ch << std::endl;
std::cout << static_cast<int>(ch) << std::endl;
return 0;
}
To get the variable or expression type.
#include <typeinfo>
int main(){
int numerator(50);
double denominator(5.0);
std::cout << typeid(numerator).name() << std::endl;
std::cout << typeid(numerator / denominator).name() << std::endl;
}
Literal
int integer(50); // integer
float f(0.05f); // used f suffix as default literal is double type
double d(0.31416); // double floating literal
int hex(0xa0); // hexadecimal literal
int oct(012); // Octal literal
int bin(0b1010); // Binary literal
int longNumber(1'23'570) // c++14 only
Constants
const double avg(6.023e23);
const double massEarth; // This is not allowed
int x(50);
const int y(x) // This is allowed
constexpr double adg(9.8); // Compile time constant. Value of the constant
// must be resolved in compile time otherwise
// will generate an error. This is c++11 feature
Variable Scopes and duration
shadowing:
int number(5);
if(number == 5){
int number; // local variable
= 10; // will effect only local variable
number // this is shadowing
std::cout << number << std::endl; // will print local
}
std::cout << number << std::endl; // will print outer block number
Global scope operator
::
is the global scope operator.
int x(50); // global variable
int main(){
int x(40);
std::cout << x << std::endl; // will print local x
std::cout << ::x << std::endl; // will print global x
}
Internal Variable: Can be used anywhere in the file they are defined but not out of the file.
External Variable: Cab be used across multiple files. Global variables are by default external. static keyword can be used to make them internal.
Console Input/Output
Console I/O Methods
std::cin
is used for console input.std::cin
takes inputs untill first whitespace.
#include <iostream>
int main(){
int selection;
std::cin >> selection;
std::cout << "You have selected: " << selection << std::endl;
return 0;
}
std::getline()
is used to take whole line as input.
#include <iostream>
#include <string>
int main(){
std::string name;
std::cout << "Enter Name: ";
std::getline(std::cin, name);
std::cout << "Your name is: " << name;
return 0;
}
Error Handling in Console Input
std::cin
takes upto newline from the input stream. So it
will be a problem if any other input function is used after taking
numeric input from std::cin.
#include <iostream>
#include <string>
int main(){
std::string name;
int select;
std::cout << "Select: ";
std::cin >> select;
std::cout << "Enter name: ";
std::getline(std::cin, name); // will not work
std::cout << "Your name is: " << name << "! You have selected: "
<< select;
return 0;
}
To solve this problem std::cin.ignore(n, ch)
can be used
where n is the number of character to ignore from the
input stream before ch character is found.
#include <iostream>
#include <string>
int main(){
int select;
std::string name;
std::cout << "Select: ";
std::cin >> select;
std::cin.ignore(32767, '\n');
std::cout << "Enter name: ";
std::getline(std::cin, name);
std::cout << "Hi " << name << "! You have selected " << select << std::endl;
return 0;
}
A Program Handling All the Error Case in Input
Expand to see code
#include <iostream>
double getDouble(){
double d;
while(true){
std::cout << "Enter: ";
std::cin >> d;
std::cin.ignore(32767, '\n'); /* clear '\n' from input stream */
/*
* Input will fail if a valid number isn't typed.
* if input fails, cin will set fail flag and stop extracting
* characters from input stream.
*/
if(std::cin.fail()){
std::cout << "Please enter a floating number" << std::endl;
std::cin.clear(); /* Clear fail flag */
std::cin.ignore(32767, '\n'); /* Clear input stream */
}
else{
return d;
}
}
}
char getOperator(){
char op;
while(true){
std::cout << "Enter (+, -, * or /): ";
std::cin >> op;
std::cin.ignore(32767, '\n');
if(op == '+' || op == '-' || op == '*' || op == '/'){
return op;
}
else{
std::cout << "Bad operator. Input again." << std::endl;
}
}
}
void printResult(double d1, char op, double d2){
if(op == '+'){
std::cout << d1 << " + " << d2 << " = " << d1 + d2 << std::endl;
}
else if(op == '-'){
std::cout << d1 << " - " << d2 << " = " << d1 - d2 << std::endl;
}
else if(op == '*'){
std::cout << d1 << " * " << d2 << " = " << d1 * d2 << std::endl;
}
else{
if(d2 != 0){
std::cout << d1 << " / " << d2 << " = " << d1 / d2 << std::endl;
}
else{
std::cout << "Can't devide by zero!";
}
}
}
int main(){
double d1 = getDouble();
char op = getOperator();
double d2 = getDouble();
(d1, op, d2);
printResult
return 0;
}
Generating Random Numbers
Generating Random Numbers
#include <iostream>
#include <ctime>
#include <cstdlib>
int main(){
/* For generating different seed each time the program runs */
(static_cast<unsigned int>(time(0)));
srandstd::cout << rand();
return 0;
}
Function for generating Random Numbers Between A Range
Using modulus:
#include <iostream>
#include <ctime>
#include <cstdlib>
int getRandom(int min, int max){
return min + (rand() % (max - min + 1));
}
int main(){
/* For generating different seed each time the program runs */
(static_cast<unsigned int>(time(0)));
srandstd::cout << getRandom(1, 6);
return 0;
}
But this method is biased to low numbers. Following method has less bias to low numbers.
#include <iostream>
#include <ctime>
#include <cstdlib>
int getRandom(int min, int max){
static const double fraction = 1.0 / RAND_MAX;
return min + ((max - min + 1) * (rand() * fraction));
}
int main(){
/* For generating different seed each time the program runs */
(static_cast<unsigned int>(time(0)));
srandstd::cout << getRandom(1, 6);
return 0;
}
For details: http://www.learncpp.com/cpp-tutorial/59-random-number-generation/
Advanced Data Types
Array
Array Indexes
Array index must be a compile time constant.
#include <iostream>
int main(){
int array[5]; // ok
#define ARR_SIZE 5
int array[ARR_SIZE]; // ok
int const arr_size = 5;
int array[arr_size]; // ok
int arr_size = 5;
}
Representing Array Indexes with Enumerators
Array index can be represented with enumerators. In this way it makes arrays well documented:
#include <iostream>
namespace Store{
enum Store{
LM7805,
MAX485,
LM311,
ATMEGA64,
LED,
MAX_ELEMENT
};
}
int main(){
int inStore[Store::MAX_ELEMENT];
inStore[Store::LM7805] = 50;
std::cout << "There are " << inStore[Store::LM7805] \
<< " LM7805 in store" << std::endl;
return 0;
}
Relation Between Array and Pointer
Arrays are actually pointers. It points to the first element of the array.
#include <iostream>
int main(){
int arr[2] = {1, 2};
/* Following two address will be same*/
std::cout << arr << std::endl;
std::cout << &arr[0] << std::endl;
return 0;
}
Difference Between Array and Pointer to Array
The type of the array is int (*)[n]
if it is an integer
array but the type of the pointer to that array is int *
.
Array type contains the size information of the array. When array is
dereferenced or assigned to a pointer it implicitly converts itself into
type *
from type (*)[n]
so size information is
lost. Here is an example of this behaviour:
#include <iostream>
int main(){
int arr[5] = {1, 2, 3, 4, 5};
int *arrPtr = arr; // arr is converted from int (*)[2] to int *
/* Will print the size of the array which is 5 * 8 bytes */
std::cout << sizeof(arr) << std::endl;
/* Will print the size of the pointer which is 8 bytes */
std::cout << sizeof(arrPtr) << std::endl;
return 0;
}
String Constants Using Fixed Sized Array and Pointer
#include <iostream>
int main(){
/*
* keep the string constant in memory with r/w access
* and return the pointer to it.
* So string constant can be changed any time later
*/
char arr[] = "hello, world";
/*
* Keep the string constant in read-only section of memory
* so it can't be changed
*/
char *text = "GNU is not Unix";
/* As it is a constant so its better to initialize following way */
const char *text = "GNU is not Unix";
[0] = 'g'; // This OK
arr
/*
* In this case as string constant is kept in read-only
* memory, doing this will generate segmentation
* fault
*/
*(text + 2) = 'O';
std::cout << arr << std::endl;
std::cout << text << std::endl;
return 0;
}
Pointers
Definig NULL Pointer C++ Way
From C++11 nullptr
keyword can be used to define a NULL
pointer.
#include <iostream>
int main(){
int *ptr = nullptr;
if(ptr){
std::cout << "Not null" << std::endl;
}
else{
std::cout << "Null" << std::endl;
}
return 0;
}
Void Pointers
- Can point to any data type
- Have to cast manually to a data type before dereferencing.
- Pointer arithmetic can’t be done using void pointers as size of the obect isn’t known
#include <iostream>
int main(){
int x(5);
void *ptr = &x; // pointing to an integer
std::cout << *static_cast<int*>(ptr) << std::endl;
char ch = 'P'; // pointing to a char
= &ch;
ptr
std::cout << static_cast<char*>(ptr) << std::endl;
return 0;
}
Converting A Pointer Address to Integer
Using reinterpret_cast<>
:
#include <iostream>
int main(){
int x = 17;
unsigned int addressX = reinterpret_cast<int>(&x);
std::cout << addressX << std::endl;
return 0;
}
Dynamic Memory Allocation
There are three basic type of memory allocation:
Static memory allocation: Static and global variables. Allocated when program runs. Persist throught the program life. Memory is taken from the stack.
Atomatic memory allocation: Function parameter and local variables. Allocated when enter into relevent block and deallocated when exited the block. Memory is taken from the stack.
Dynamic memory allocation: Memory allocated and deallocated dynamically. Memory is taken from the heap.
Allocating Memory dynamically
Dynamically memory is allocated using the new
keyword.
#include <iostream>
int main(){
int *ptr = new int; // dynamically an integer is allocated.
*ptr = 5;
return 0;
}
Deallocating memory
Memory is deallocated using the delete
keyword.
#include <iostream>
int main(){
int *ptr = new int(5); // memory is allocated to the pointer
/* memory is deallocated.
* memory is realesed by os.
*/
delete ptr;
/* still the pointer is holding the memory address
* so its better to make it null
*/
= 0;
ptr = nullptr; // c++11
ptr
return 0;
}
Memory leak
memory leak happens when allocated memory can’t be deallocated.
#include <iostream>
void doSomthing(){
/* Memory is allocated but not deallocated
* so memory leak happens when the variable
* goes out of scope as there is no way
* to deallocate in that case
*/
int *ptr = new int;
}
int main(){
();
doSomthingreturn 0;
}
#include <iostream>
int main(){
int *ptr = int new;
int val;
// assigning to a address with out deallocating
= &val; // memory leak
ptr
return 0;
}
#include <iostream>
int main(){
int *ptr = new int(5);
// allocating new memory without deallocating previous one
int *ptr = new int(10);
return 0;
}
Reference Variables
Create alias for a variable. Basically share same memory address. Must be initialized with an addressable object. Can be used in function to pass parameter by reference.
#include <iostream>
int main(){
int x(10);
int &y = x; // reference variable
/*
* will output:
* 10
* 10
*/
std::cout << x << std::endl
std::cout << y << std::endl
return 0;
}
For Each Loop
- Only works from c++11 above
- Can’t be used in case of decayed arrays and dynamically allocated arrays.
#include <iostream>
int main(){
int fibseq[] = {1, 1, 2, 3, 5, 8, 13, 21};
std::cout << "Fibonacci Sequence: ";
for(const auto &elem: fibseq){
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
Functions
Function Pointers
#include <iostream>
int foo(int x){
return x*x;
}
int main(){
int (*square)(int) = foo;
std::cout << square(10) << std::endl;
return 0;
}
- Can’t be used for function’s with default arguments
Function Ellipsis
Ellipsis can be used to pass variable length argument in a function.
#include <iostream>
#include <cstdarg> // to use ellipsis
void printNum(int count, ...){
va_list list;
(list, count);
va_start
for(int arg = 0; arg < count; arg++){
std::cout << va_arg(list, int) << std::endl;
}
(list);
va_end}
int main(){
(5, 1, 2, 3, 4, 5);
printNum
return 0;
}
- Ellipsis are dangerous. Try to avoid them. For more – http://www.learncpp.com/cpp-tutorial/714-ellipsis-and-why-to-avoid-them/
Lambda Functions
To create anonymous functions. Simple example:
#include <iostream>
#include <algorithm>
#include <vector>
int main(int argc, char *argv[]) {
std::vector<bool> bitvect{1, 0, 0, 1};
/* lambda function example: used to make ~bitvect */
std::transform(bitvect.begin(), bitvect.end(), bitvect.begin(),
[](bool b){ return b == 1 ? 0 : 1; });
return 0;
}
Syntaxt:
[&](){}
: Capture all outside variable by reference.
[=](){}
: Capture all outside variable by value.
[&x](){}
: Capture only outside variable x
by reference. [x](){}
: Capture only outside variable
x
by value. [&, x](){}
: Capture all
outside variable by reference but x
by value.
[]() -> Type {}
: To specify return type.
Object Oriented Programming
Basic Class Example
#include <iostream>
class Point{
private:
double m_x;
double m_y;
public:
double getX(){
return m_x;
}
void setX(double x){
m_x = x;
}
double getY(){
return m_y;
}
void setY(double y){
m_y = y;
}
};
int main(){
;
Point p
.setX(-2.5);
p.setY(2.5);
p
std::cout << "(" << p.getX() << ", " << p.getY() << ")" << std::endl;
return 0;
}
Constructors
#include <iostream>
class Point{
private:
double m_x;
double m_y;
public:
(double x = 0, double y = 0): m_x(x), m_y(y){
Point// empty
}
double getX(){
return m_x;
}
void setX(double x){
m_x = x;
}
double getY(){
return m_y;
}
void setY(double y){
m_y = y;
}
void printPoint(){
std::cout << "(" << m_x << ", " << m_y << ")" << std::endl;
}
};
int main(){
(0.5, 0.5);
Point p
.printPoint();
p
return 0;
}
In c++11 its possible to give default value in class memeber variable declaration.
#include <iostream>
class Point{
private:
double m_x = 0; // default value of x
double m_y = 0; // default value of y
public:
// member variable will be initialized with default value
// if called
(){
Point//empty
}
double getX(){
return m_x;
}
void setX(double x){
m_x = x;
}
double getY(){
return m_y;
}
void setY(double y){
m_y = y;
}
void printPoint(){
std::cout << "(" << m_x << ", " << m_y << ")" << std::endl;
}
};
int main(){
; // will call default constructor
Point p
.printPoint();
p
return 0;
}
Destructors
#include <iostream>
#include <cassert>
class Point{
private:
double m_x;
double m_y;
public:
(double x = 0, double y = 0): m_x(x), m_y(y){
Point//empty
}
double getX(){
return m_x;
}
void setX(double x){
m_x = x;
}
double getY(){
return m_y;
}
void setY(double y){
m_y = y;
}
void printPoint(){
std::cout << "(" << m_x << ", " << m_y << ")" << std::endl;
}
};
class PointArray{
private:
*m_points;
Point int m_length;
public:
(int length){
PointArraym_points = new Point[length];
m_length = length;
}
// Destructor
~PointArray(){
delete[] m_points;
}
void insert(Point &p, int index){
assert(index >= 0 && index < m_length);
m_points[index] = p;
}
& get(int index){
Pointassert(index >= 0 && index < m_length);
return m_points[index];
}
};
int main(){
(5);
PointArray parr
(2, 3);
Point p;
Point q
.insert(p, 0);
parr
= parr.get(0);
q .printPoint();
q
return 0;
}
Static Member Variables
- Will shared by all object.
- Not bound to any object. Bound to the whole class. So it is possible to use this variable without any object.
#include <iostream>
class Static{
public:
static int id;
};
/* Have to initialize first otherwise linker error will generate */
int Static::id = 1;
int main(){
;
Static s;
Static t
/* Shared by both object */
.id = 5;
sstd::cout << s.id << "\t" << t.id << std::endl;
/* Bound to whole class */
::id = 10;
Staticstd::cout << s.id << "\t" << t.id << std::endl;
return 0;
}
Static Member Functions
- Not bound to any object.
#include <iostream>
class ID{
private:
static int m_id;
public:
static int getID(){
return m_id;
}
};
/* Have to initialize first otherwise linker error will generate */
int ID::m_id = 1;
int main(){
std::cout << ID::getID << std::endl;
return 0;
}
Member Types
In C++ classes can have memeber types or nested types. They make the class easy to maintain. For example in the following example it will be easy to change the type from int to double. It need to change in only one line.
#include <iostream>
class Point{
public:
using point_t = int; // Member type
(point_t x, point_t y): m_x(x), m_y(y){}
Point
void print(void){
std::cout << "(" << m_x << ", " << m_y << ")";
}
private:
point_t m_x;
point_t m_y;
};
int main(int argc, char *argv[]){
(10, 20);
Point p.print();
preturn 0;
}
Access Specifiers
public: private: protected:
Chaining member functions
#include <iostream>
class Point{
public:
using point_t = int;
(point_t x, point_t y): m_x(x), m_y(y){}
Point
& add(point_t x, point_t y){
Pointthis->m_x += x;
this->m_y += y;
return *this;
}
& mul(point_t x, point_t y){
Pointthis->m_x *= x;
this->m_y *= y;
return *this;
}
void print(void){
std::cout << "(" << m_x << ", " << m_y << ")";
}
private:
point_t m_x;
point_t m_y;
};
int main(int argc, char *argv[]){
(10, 20);
Point p.add(3, 5).mul(7, 8).add(2, 3);
p.print();
preturn 0;
}
Difference between structs and classes in C++
C++ structs and classes are same. Only difference is that all members in structs are public.
Friend function and friend class
Friend functions and classes can access the private members of a
class. In the following example printWeather()
is friend of
both Humidity
and Temperature
class. So it can
access private members of both classes.
#include <iostream>
class Humidity;
class Temperature
{
private:
int m_temp;
public:
(int temp=0) { m_temp = temp; }
Temperature
friend void printWeather(const Temperature &temperature, const Humidity &humidity);
};
class Humidity
{
private:
int m_humidity;
public:
(int humidity=0) { m_humidity = humidity; }
Humidity
friend void printWeather(const Temperature &temperature, const Humidity &humidity);
};
void printWeather(const Temperature &temperature, const Humidity &humidity)
{
std::cout << "The temperature is " << temperature.m_temp <<
" and the humidity is " << humidity.m_humidity << '\n';
}
int main()
{
(10);
Humidity hum(12);
Temperature temp
(temp, hum);
printWeather
return 0;
}
Classes can also be friend of another class. In following example
Display
class if a friend of Storage
class so
it can access the private members.
#include <iostream>
class Storage
{
private:
int m_nValue;
double m_dValue;
public:
(int nValue, double dValue)
Storage{
m_nValue = nValue;
m_dValue = dValue;
}
// Make the Display class a friend of Storage
friend class Display;
};
class Display
{
private:
bool m_displayIntFirst;
public:
(bool displayIntFirst) { m_displayIntFirst = displayIntFirst; }
Display
void displayItem(const Storage &storage)
{
if (m_displayIntFirst)
std::cout << storage.m_nValue << " " << storage.m_dValue << '\n';
else // display double first
std::cout << storage.m_dValue << " " << storage.m_nValue << '\n';
}
};
int main()
{
(5, 6.7);
Storage storage(false);
Display display
.displayItem(storage);
display
return 0;
}
Operator Overloading
In C++ each operator is actually a function. For example the operator
+
is acturally operator+()
function.
- At least one of the operand will have to be a custom type
Using Friend Function
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
Point
// constant memeber function
void print(void) const {
std::cout << "(" << m_x << ", " << m_y << ")" << "\n";
}
// This is not a member function only a friend function
// This could defined outside of the function too
friend Point operator+(cost Point &p, const int n){
return Point(p.m_x + n, p.m_y + n);
}
friend Point operator+(const int n, const Point &p){
return p + n;
}
friend Point operator+(const Point &p1, const Point &p2){
return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y);
}
};
int main(int argc, char *argv[]){
(10, 20);
Point p1(4, 5);
Point p2= p1 + p2 + 5;
Point p3
.print();
p3
return 0;
}
Using Normal Function
If there is no need to access private class data, operator overloading can be done as normal function.
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
Point
point_t getX(void) const {
return m_x;
}
point_t getY(void) const {
return m_y;
}
// constant memeber function
void print(void) const {
std::cout << "(" << m_x << ", " << m_y << ")" << "\n";
}
};
operator+(const Point &p, const int n){
Point return Point(p.getX() + n, p.getY() + n);
}
operator+(int n, const Point &p){
Point return p + n;
}
operator+(const Point &p1, const Point &p2){
Point return Point(p1.getX() + p2.getX(), p1.getY() + p2.getY());
}
int main(int argc, char *argv[]){
(10, 20);
Point p1(4, 5);
Point p2= p1 + p2 + 5;
Point p3
.print();
p3
return 0;
}
Using Member Function
The assignment (=), subscript ([]), function call (()), and member selection (->) operators must be overloaded as member functions. IO operators(<< and >>) can’t be overloaded as memeber functions.
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
Point
// No need to pass the class explicitly as it will be passed as hidden this pointer
operator+ (int n){
Point return Point(m_x + n, m_y +n);
}
};
int main(int argc, char *argv[]){
(10, 20);
Point p1= p1 + 5;
Point p2 return 0;
}
Overloading IO operators
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
Point
point_t getX(void){
return m_x;
}
point_t getY(void){
return m_y;
}
friend std::ostream& operator<< (std::ostream &out, const Point &p);
friend std::istream& operator>> (std::istream &in, Point &p);
};
// Overloading as friend function
// Returning std::ostream so that it can be chained like std::cout << p1 << p2
std::ostream& operator<< (std::ostream &out, const Point &p){
<< "(" << p.m_x << ", " << p.m_y << ")";
out return out;
}
std::istream& operator>> (std::istream &in, Point &p){
>> p.m_x >> p.m_y;
in return in;
}
// Overloading as normal function
operator+ (Point p, int n){
Point return Point(p.getX() + n, p.getY() + n);
}
operator+ (int n, Point p){
Point return p + n;
}
operator+ (Point p1, Point p2){
Point return Point(p1.getX() + p2.getX(), p1.getY() + p2.getY());
}
int main(int argc, char *argv[]){
(10, 20);
Point p1;
Point p2
std::cout << "Enter a point:\n";
std::cin >> p2;
std::cout << p1 << " + " << p2 << " = " << p1 + p2 << "\n";
return 0;
}
Functors
When classes acts like function calls they are called functors. This can be done by overloading () operator.
#include <iostream>
class Point{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
(): m_x(0), m_y(0){}
Point(point_t x, point_t y): m_x(x), m_y(y){}
Point
point_t getX(void){
return m_x;
}
point_t getY(void){
return m_y;
}
// () can only be overloaded as member function
operator() (int n){
Point return Point(m_x + n, m_y + n);
}
friend std::ostream& operator<< (std::ostream &out, const Point &p);
};
// Overloading as friend function
// Returning std::ostream so that it can be chained like std::cout << p1 << p2
std::ostream& operator<< (std::ostream &out, const Point &p){
<< "(" << p.m_x << ", " << p.m_y << ")";
out return out;
}
int main(int argc, char *argv[]){
(10, 20);
Point pnt
// Will add 5 to pnt.m_x, pnt.m_y and create new Point object.
// Notce class object is called like function.
std::cout << pnt(5) << "\n";
return 0;
}
Overloading Typecast
Typecast overloading can be done to convert between types.
#include <iostream>
#include <cmath>
class Polar{
private:
double m_r;
double m_theta;
public:
(double r, double theta): m_r(r), m_theta(theta){}
Polarfriend std::ostream& operator<< (std::ostream &out, const Polar &p);
};
// Overloading as friend function
// Returning std::ostream so that it can be chained like std::cout << p1 << p2
std::ostream& operator<< (std::ostream &out, const Polar &p){
<< "(" << p.m_r << ", " << p.m_theta << ")";
out return out;
}
class Cartesian{
private:
using point_t = int;
point_t m_x;
point_t m_y;
public:
(): m_x(0), m_y(0){}
Cartesian(point_t x, point_t y): m_x(x), m_y(y){}
Cartesian
friend std::ostream& operator<< (std::ostream &out, const Cartesian &c);
// Typecast overloading
operator Polar() const {
double r = sqrt(pow(m_x, 2) + pow(m_y, 2));
double theta = atan(static_cast<double>(m_y) / static_cast<double>(m_x));
= (theta * 180) / M_PI;
theta
return Polar(r, theta);
}
};
std::ostream& operator<< (std::ostream &out, const Cartesian &c){
<< "(" << c.m_x << ", " << c.m_y << ")";
out return out;
}
int main(int argc, char *argv[]){
(10, 20);
Cartesian cart(cart);
Polar pol
std::cout << "Cartesian: " << cart << "\tPolar: " << pol << "\n";
return 0;
}
Copy Constructors
When copy initialization is used a copy constructor is used. By default compiler uses memberwise initialization if no copy constructor is provided. For example:
class Xyz {
private:
int m_var;
public:
(int x): m_var(x){}
Xyz};
int main(void){
(10); // uses default initialization
Xyz xy
(xy); // Copy initialization
Xyz yz// As there is no copy constructor provided, compiler will do a memberwise initialization
}
Member functions of a class can access the private members ot the same class type. Here is an example with copy constructor:
class Xyz {
private:
int m_var;
public:
(int x): m_var(x){}
Xyz
// Copy constructor
(const Xyz &xyz): m_var(xyz.m_var){}
Xyz};
int main(void){
(10); // uses default initialization
Xyz xy
(xy); // uses copy constructor
Xyz yz}
Elision
Copy initialization should be avoided as it can be elided for optimization.
#include <iostream>
#include <string>
class Hello{
private:
std::string m_s;
public:
(std::string s): m_s(s){}
Hello
(const Hello &h): m_s(h.m_s){
Hellostd::cout << "Copy constructor called\n";
}
std::string get(void){return m_s;}
};
int main(int argc, char *argv[]){
("hello");
Hello h(h); // Copy constructor will be used
Hello g= Hello("gello"); // Copy constructor won't be used
Hello i (Hello("gello")); // Copy constructor won't be used
Hello k
std::cout << h.get() << g.get() << i.get() << k.get() << "\n";
}
If a class is passed by value in a function and return by value from a function copy constructor will be called. For example:
(Hello h){ // Copy constructor will be called
Hello changeHello.change("new hello");
hreturn h; // Copy constructor will be called
}
Implicit conversion, explicit and delete keyword
- explicit keyword can be used to prevent implicit conversion.
- delete keyword can be used to prevent both implicit and explicit conversion.
- For details
Overloading assignment operator
- Can only be oveloaded as memeber function.
- Watch out for self assignment.
- If no overloaded assignment operator is provided, compiler will do memberwise copy.
#include <iostream>
#include <string>
class Hello{
private:
std::string m_s;
public:
(std::string s): m_s(s){}
Hello
(const Hello &h): m_s(h.m_s){
Hellostd::cout << "Copy constructor called\n";
}
std::string get(void){return m_s;}
& operator= (const Hello &h){
Hello// If self copying
if(this == &h)
return *this; // for chainig
m_s = h.m_s;
return *this; // for chaining
}
};
int main(int argc, char *argv[]){
("hello");
Hello h("iello");
Hello i("jello");
Hello j(h); // Copy constructor is called
Hello k
= i = h; // Overloaded function is called
j
std::cout << h.get() << i.get() << j.get() << k.get() << "\n";
}
Shallow copy VS Deep copy
- Shallow copy means memberwise copying by the compiler if no copy constructor or overloaded assingment operator is provided.
- The default copy constructor and default assignment operators do shallow copies, which is fine for classes that contain no dynamically allocated variables.
- Classes with dynamically allocated variables need to have a copy constructor and assignment operator that do a deep copy.
Object Relationship
Composition and Aggregation
In both cases relationship between parent and child is ‘has a’.
Composition
The part (member) is part of the object (class)
The part (member) can only belong to one object (class) at a time
The part (member) has its existence managed by the object (class)
The part (member) does not know about the existence of the object (class)
Typically use normal member variables
Can use pointer members if the class handles object allocation/deallocation itself
Responsible for creation/destruction of parts
Aggregation
The part (member) is part of the object (class)
The part (member) can belong to more than one object (class) at a time
The part (member) does not have its existence managed by the object (class)
The part (member) does not know about the existence of the object (class)
Typically use pointer or reference members that point to or reference objects that live outside the scope of the aggregate class
Not responsible for creating/destroying parts
Association
- The associated object (member) is otherwise unrelated to the object (class)
- The associated object (member) can belong to more than one object (class) at a time
- The associated object (member) does not have its existence managed by the object (class)
- The associated object (member) may or may not know about the existence of the object (class)
Dependencies
A dependency occurs when one object invokes another object’s functionality in order to accomplish some specific task. This is a weaker relationship than an association, but still, any change to object being depended upon may break functionality in the (dependent) caller. A dependency is always a unidirectional relationship.
Container Classes
Hold and organize multiple instance of another type(class or fundamental type).
std::initializer_list
Used in container class’s constructor for list initialization.
Inheritance
Order of construction
Most base class constructed first and most derived class constructed last.
#include <iostream>
class Parent{
public:
(){
Parentstd::cout << "A" << "\n";
}
};
class Child: public Parent{
public:
(){
Childstd::cout << "B" << "\n";
}
};
int main(int argc, char *argv[]){
;
Child creturn 0;
}
/*
* Will print:
* A
* B
*/
When a derived class is instanciated following things happen in order:
- Memory for derived is set aside (enough for both the Base and Derived portions)
- The appropriate Derived constructor is called
- The Base object is constructed first using the appropriate Base constructor. If no base constructor is specified, the default constructor will be used.
- The initialization list initializes variables
- The body of the constructor executes
- Control is returned to the caller
Constructors and initialization of derived classes
#include <iostream>
class Parent{
public:
int m_x;
(int x=0): m_x(x){
Parentstd::cout << "A" << "\n";
}
};
class Child: public Parent{
public:
int m_y;
// Parent will be initialized with defautl vlaue
(int y=0): m_y(y){
Childstd::cout << "B" << "\n";
}
// Parent will be initialized with given value
(int x, int y): Parent(x), m_y(y){
Childstd::cout << "B" << "\n";
}
};
int main(int argc, char *argv[]){
// Parent's default constructor will be called
(10);
Child c
// Parent will be initialized with given value
(20, 10);
Child d
// Will print
// Parent 0
// Child 10
std::cout << "Parent " << c.m_x << "\nChild " << c.m_y << "\n";
// Will print
// Parent 20
// Child 10
std::cout << "Parent " << d.m_x << "\nChild " << d.m_y << "\n";
return 0;
}
When Child d(10, 20)
is called following things
happended:
- Memory for Child is allocated.
- The Child(int, int) constructor is called, where x = 10, and y = 20
- The compiler looks to see if we’ve asked for a particular Base class constructor. We have! So it calls Parent(int) with x = 10.
- The base class constructor initialization list sets m_x to 10
- The base class constructor body executes, which prints A
- The base class constructor returns
- The derived class constructor initialization list sets m_y to 20
- The derived class constructor body executes, which prints B
- The derived class constructor returns
Order of Destruction
Destructors are called in reverse order of construction.
Inheritance and Access Specifiers
- public: Can be accessed by anybody.
- protected: Can be accessed by class member functions, friend functions and derived classes.
- private: Can be accessed by only class member functions and friend functions.
A summary of the behavious when inherited publicly, protectedly or privately:
Access Specifier in Base Class | Inherited Publicly | Inherited Protectedly | Inherited Privately |
---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
private | inaccessible | inaccessible | inaccessible |
Overriding Behavior
Redefining
#include <iostream>
class Base{
public:
(){}
Base
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
(){}
Derived
void identify(void){
std::cout << "I am derived\n";
}
};
int main(int argc, char *argv[]){
;
Derived d
// Will print I am derived
.identify();
d
return 0;
}
- Redefined functions doesn’t inherite access specification from parent.
Expanding Existing Functionality
#include <iostream>
class Base{
public:
(){}
Base
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
(){}
Derived
void identify(void){
// if scope isn't used Derived::identify() will be called
::identify();
Basestd::cout << "I am derived\n";
}
};
int main(int argc, char *argv[]){
;
Derived d
// Will print
// I am base
// I am derived
.identify();
d
return 0;
}
Changing an Inherited Member’s Access Specification
#include <iostream>
class Base{
public:
(){}
Base
protected:
// Only membes, friends and derived class can call
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
(){}
Derived
// Base::identify() is now public
using Base::identify;
};
int main(int argc, char *argv[]){
;
Base b;
Derived d
// Error: can't call from here
.identify();
b
// OK: as it is public in Derived class
.identify();
d
return 0;
}
Functionality can be hidden by making it private in derived class.
#include <iostream>
class Base{
public:
(){}
Base
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
(){}
Derived
private:
// Base::identify() is now private
using Base::identify;
};
int main(int argc, char *argv[]){
;
Base b;
Derived d
// OK: as it is public in Base class.
.identify();
b
// OK: as it is public in Derived class
.identify();
d
return 0;
}
Multiple Inheritance
- Ambiguity can arise.
#include <iostream>
class USBDevice
{
private:
long m_id;
public:
(long id)
USBDevice: m_id(id)
{
}
long getID() { return m_id; }
};
class NetworkDevice
{
private:
long m_id;
public:
(long id)
NetworkDevice: m_id(id)
{
}
long getID() { return m_id; }
};
class WirelessAdapter: public USBDevice, public NetworkDevice
{
public:
(long usbId, long networkId)
WirelessAdapter: USBDevice(usbId), NetworkDevice(networkId)
{
}
};
int main()
{
(5442, 181742);
WirelessAdapter c54Gstd::cout << c54G.getID(); // Which getID() do we call?
// Can be solved using scope
std::cout << c54G.USBDevice::getID();
return 0;
}
- Diamond problem
Virtual Functions
Pointers to the Base Class of Derived Object
It is possible to create pointers to the base class of derived object. But the pointers won’t be able to call member functions from the derived class.
#include <iostream>
class Base{
public:
(){}
Base
void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
(){}
Derived
void identify(void){
std::cout << "I am derived\n";
}
};
int main(int argc, char *argv[]){
*pd = new Derived();
Derived // Pointer to base of derived object
*pb{pd};
Base
// Will call Derived::indentify()
->identify();
pd
// Will call Base::identify()
->identify();
pb
return 0;
}
Use case for this could be in functions which takes derived class as parameter. For each derived class a different functions have to be created. For example:
void report(Derived &d){
.identify();
d}
void report(AnotherDerived &ad){
.identify();
ad}
This problem can be solved using pointer/reference to base:
void report(Base &b){
.identify();
b}
int main(int argc, char *argv[]){
;
Derived d;
AnotherDerived ad
(d);
report(ad);
report}
But the problem is in both cases Base::identify() will be called. As pointer to base only can see memebers from base. This problem can be solved using virtual functions.
Polymorphism
A virtual function is a special type of function that, when called, resolves to the most-derived version of the function that exists between the base and derived class. This capability is known as polymorphism. A derived function is considered a match if it has the same signature (name, parameter types, and whether it is const) and return type as the base version of the function. Such functions are called overrides.
#include <iostream>
class Base{
public:
(){}
Base
virtual void identify(void){
std::cout << "I am base\n";
}
};
class Derived: public Base{
public:
(){}
Derived
void identify(void){
std::cout << "I am derived\n";
}
};
class AnotherDerived: public Derived{
public:
(){}
AnotherDerived
void identify(void){
std::cout << "I am another derived\n";
}
};
int main(int argc, char *argv[]){
;
AnotherDerived ad*bp = &ad;
Base
// Both resolve to AnotherDerived::identify()
.identify();
ad->identify();
bp
;
Derived d= &d;
bp
// Resolve to Derived::identity() as it is the most derived class in this case
->identify();
bp
return 0;
}
Another example:
#include <iostream>
#include <string>
class Base{
public:
(){}
Base
virtual std::string getName(void) const {return "Base";}
};
class Derived: public Base{
public:
(){}
Derived
virtual std::string getName(void) const {return "Derived";}
};
class AnotherDerived: public Derived{
public:
(){}
AnotherDerived
virtual std::string getName(void) const {return "AnotherDerived";}
};
void report(Base &b){
std::cout << "I am " << b.getName() << "\n";
}
int main(int argc, char *argv[]){
;
Derived d;
AnotherDerived ad
(d);
report(ad);
report
return 0;
}
If you want to call functions from base class in virtual function just use scope operator:
Derived d;
Base *bp = &d;
std::cout << bp->Base::getName() << "\n";
- Return type have to match between virtual functions.
- Never use virtual function in constructors and destructors.
override and final Specifiers
A derived virtual function is only considered override if functino
signature and return type matches exactly between the virtual functions.
override
specifier enforces virtualization of a function.
If signature and return type doesn’t match the compiler will generate an
error. If override
is used, no need to specify
virtual
keyword.
Covariant Return Type
Destructors
In case of inheritance destructors should always make virtual. Specially if there is dynamically allocated memory involved. If a derived class is converted to a base class and then call delete, only base destructor will be called. If dynamic memory is allocated in derived class, this will leak memory.
Abstract Class, Pure Virtual Functions and Interface Class
Abstract class is a class wich is only used by the derived class. It can’t be instantiated anywhere else.
A pure virtual function has no body at all. It is meant to be redefined in derived classes. A class with pure virtual functions is an abstract class means it can’t be intantiated. A pure virtual function may or may not have a body.
virtual void doSomething() = 0
In interface class has no member variables. All the functions are pure virtual.
Virtual Base Class
- Single Base class is shared by the derived classes.
- Solves diamond problem.
- Most derived class is responsible for constructing the virtual base class.
Example:
#include <iostream>
class PoweredDevice
{
public:
PoweredDevice(int power)
{
std::cout << "PoweredDevice: " << power << '\n';
}
};
class Scanner: virtual public PoweredDevice // note: PoweredDevice is now a virtual base class
{
public:
Scanner(int scanner, int power)
: PoweredDevice{ power } // this line is required to create Scanner objects, but ignored in this case
{
std::cout << "Scanner: " << scanner << '\n';
}
};
class Printer: virtual public PoweredDevice // note: PoweredDevice is now a virtual base class
{
public:
Printer(int printer, int power)
: PoweredDevice{ power } // this line is required to create Printer objects, but ignored in this case
{
std::cout << "Printer: " << printer << '\n';
}
};
class Copier: public Scanner, public Printer
{
public:
Copier(int scanner, int printer, int power)
: PoweredDevice{ power }, // PoweredDevice is constructed here
Scanner{ scanner, power }, Printer{ printer, power }
{
}
};
Object Slicing
;
Derived d(d); // b will get the Base part from d. It is called object slicing
Base b
// Will call Base::doSomething() even if it is a virtual function
.doSomething()
b
&b(d);
Base
// Will call Derived::doSomething if it is a virtual function as b in reference to d
->doSomething() bp
- In general avoid slicing
std::reference_wrapper
Dynamic Casting
Dynamic casing is used for downcasting.
Workaround for Friend Functions
Only member functions can be virtualized. So friend functions can’t be virtualized. For example:
#include <iostream>
class Base
{
public:
() {}
Base
// Here's our overloaded operator<<
friend std::ostream& operator<<(std::ostream &out, const Base &b)
{
// Delegate printing responsibility for printing to member function print()
return b.print(out);
}
// We'll rely on member function print() to do the actual printing
// Because print is a normal member function, it can be virtualized
virtual std::ostream& print(std::ostream& out) const
{
<< "Base";
out return out;
}
};
class Derived : public Base
{
public:
() {}
Derived
// Here's our override print function to handle the Derived case
virtual std::ostream& print(std::ostream& out) const override
{
<< "Derived";
out return out;
}
};
int main()
{
;
Base bstd::cout << b << '\n';
;
Derived dstd::cout << d << '\n'; // note that this works even with no operator<< that explicitly handles Derived objects
&bref = d;
Base std::cout << bref << '\n';
return 0;
}
Templates
Function Template
#include <iostream>
template <typename T>
(T x, T y){
T addreturn x + y;
}
int main(int argc, char *argv[]){
std::cout << add(1, 2) << "\n";
std::cout << add(1.5, 2.1) << "\n";
return 0;
}
For more than one type:
template <typename T1, typename T2>
void doSomething(T1 x, T1 y){
}
Class Template
#include <iostream>
#include <string>
template <class T>
class Value{
private:
m_x;
T
public:
(T x): m_x(x){}
Value
(void){return m_x;}
T get};
int main(int argc, char *argv[]){
<int> ival(10);
Value<double> dval(10.25);
Value<std::string> sval("hello");
Value
std::cout << "ival: " << ival.get() << " dval: " << dval.get() << " sval: " << sval.get()
<< "\n";
return 0;
}
If template class definition and implementation are splitted into seperate files linker error can be generated. To solve this following can be done:
- Definition and implementation in one file.
- Implementation in
*.inl
file and#include
in*.h
file.
For more details
Template Non-Type parameters
#include <iostream>
template <class T, int size> // size is the non-type parameter
class StaticArray
{
private:
// The non-type parameter controls the size of the array
m_array[size];
T
public:
* getArray();
T
& operator[](int index)
T{
return m_array[index];
}
};
// Showing how a function for a class with a non-type parameter is defined outside of the class
template <class T, int size>
* StaticArray<T, size>::getArray()
T{
return m_array;
}
int main()
{
// declare an integer array with room for 12 integers
<int, 12> intArray;
StaticArray
// Fill it up in order, then print it backwards
for (int count=0; count < 12; ++count)
[count] = count;
intArray
for (int count=11; count >= 0; --count)
std::cout << intArray[count] << " ";
std::cout << '\n';
// declare a double buffer with room for 4 doubles
<double, 4> doubleArray;
StaticArray
for (int count=0; count < 4; ++count)
[count] = 4.4 + 0.1*count;
doubleArray
for (int count=0; count < 4; ++count)
std::cout << doubleArray[count] << ' ';
return 0;
}
Template Specialization
If an exception is needed to make for an specific type.
#include <iostream>
#include <string>
#include <cstring>
char str[100];
template <class T>
(T x, T y){
T addreturn x + y;
}
// If it is an const char*
template<>
const char *add(const char *s1, const char *s2){
(str, s1);
strcat(str, s2);
strcatreturn str;
}
int main(int argc, char *argv[]){
std::cout << add(1, 2) << "\n";
std::cout << add(1.5, 2.2) << "\n";
std::cout << add("hello", "world") << "\n";
return 0;
}
Standard Template Library
Appendix A: Some Usefull Functions
decltype(s)
– Query the type of s
C++ 讲义
讲义第一部分
- C++概述
- 1.1 C++简介
- 1.2 C++起源
- 1.3 可移植性和标准
- 1.4 为什么C++会成功
- C++初识
- 2.1 简单的C++程序
- 2.1.1 c++ hello world
- 2.1.2 面向过程
- 2.1.3 面向对象
- 2.1.4 面向对象三大特性
- C++对C的扩展
- 3.1 ::作用域运算符
- 3.2 名字控制
- 3.3 全局变量检测增强
- 3.4 C++中所有的变量和函数都必须有类型
- 3.5 更严格的类型转换
- 3.6 struct类型加强
- 3.7 “新增”bool类型关键字
- 3.8 三目运算符功能增强
- 3.9 C/C++中的const
- 3.9.1 const概述
- 3.9.2 C/C++中const的区别
- const概述
- C中的const
- 尽量以const替换#define
- 3.10 引用(reference) 1. 引用基本用法 2. 函数中的引用 3. 引用的本质 4. 指针引用 5. 常量引用
- 3.11 练习作业
- 3.12 内联函数(inline function)
- 3.13 函数的默认参数
- 3.14 函数的占位参数
- 3.15 函数重载(overload)
- 3.15.1 函数重载概述
- 3.15.2 函数重载
- 3.15.3 extern “C”浅析
- 类和对象
- 4.1 类和对象的基本概念
- 4.1.1 C和C++中struct区别
- c语言struct只有变量
- c++语言struct 既有变量,也有函数
- 4.1.2 类的封装
- 4.1.3 将成员变量设置为private
- 4.1.4 课堂练习
- 4.1.1 C和C++中struct区别
- 4.2 面向对象程序设计案例
- 4.3 对象的构造和析构
- 4.4 C++面向对象模型初探
- 4.5 友元
- 4.6 运算符重载
- 4.7 继承和派生
- 4.8 多态
- 4.1 类和对象的基本概念
讲义第二部分
- 1.C++模板
- 2.C++类型转换
- C++异常
- c++输入和输出流
STL基础教程
- STL概论
- STL三大组件
- 常用容器
- 常用算法
- STL综合案例(学校演讲比赛)
C++简介
"c++"中的++来自于c语言中的递增运算符++,该运算符将变量加1。c++起初也叫"c with clsss".通过名称表明,c++是对C的扩展,因此c++是c语言的超集,这意味着任何有效的c程序都是有效的c++程序。c++程序可以使用已有的c程序库。
库是编程模块的集合,可以在程序中调用它们。库对很多常见的编程问题提供了可靠的解决方法,因此可以节省程序员大量的时间和工作量。
c++语言在c语言的基础上添加了面向对象编程和泛型编程的支持。c++继承了c语言高效,简洁,快速和可移植的传统。
c++融合了3种不同的编程方式:
- c语言代表的过程性语言.
- c++在c语言基础上添加的类代表的面向对象语言.
- c++模板支持的泛型编程。
c语言和c++语言的关系:
c++语言是在C语言的基础上,添加了面向对象、模板等现代程序设计语言的特性而发展起来的。两者无论是从语法规则上,还是从运算符的数量和使用上,都非常相似,所以我们常常将这两门语言统称为"C/C++"。
C语言和C++并不是对立的竞争关系:
- C++是C语言的加强,是一种更好的C语言。
- C++是以C语言为基础的,并且完全兼容C语言的特性。
c语言和C++语言的学习是可以相互促进。学好C语言,可以为我们将来进一步地学习C++语言打好基础,而C++语言的学习,也会促进我们对于C语言的理解,从而更好地运用C语言。
#### C/C++全栈笔记
- 进程间通讯(IPC)方法
- 管道(使用最简单)
- 信号(开销最小)
- 共享映射区(无血缘关系)
- 本地套接字(最稳定)
- 管道
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:
1. 数据一旦被读走,便不在管道中存在,不可反复读取。
2. 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
3. 只能在有公共祖先的进程间使用管道。
常见的通信方式有,单工通信、半双工通信、全双工通信。
pipe函数
- 信号
- 共享映射区
- 本地套接字
- 网络编程-网络基础
- 协议的概念
- 网络应用程序设计模式
- C/S模式
传统的网络应用设计模式,客户机(client)/服务器(server)模式。需要在通讯两端各自部署客户机和服务器来完成数据通信。
- B/S模式
浏览器()/服务器(server)模式。只需在一端部署服务器,而另外一端使用每台PC都默认配置的浏览器即可完成数据的传输。
- 优缺点
对于C/S模式来说,其优点明显。客户端位于目标主机上可以保证性能,将数据缓存至客户端本地,从而提高数据传输效率。且,一般来说客户端和服务器程序由一个开发团队创作,所以他们之间所采用的协议相对灵活。可以在标准协议的基础上根据需求裁剪及定制。例如,腾讯公司所采用的通信协议,即为ftp协议的修改剪裁版。
因此,传统的网络应用程序及较大型的网络应用程序都首选C/S模式进行开发。如,知名的网络游戏魔兽世界。3D画面,数据量庞大,使用C/S模式可以提前在本地进行大量数据的缓存处理,从而提高观感。
C/S模式的缺点也较突出。由于客户端和服务器都需要有一个开发团队来完成开发。工作量将成倍提升,开发周期较长。另外,从用户角度出发,需要将客户端安插至用户主机上,对用户主机的安全性构成威胁。这也是很多用户不愿使用C/S模式应用程序的重要原因。
B/S模式相比C/S模式而言,由于它没有独立的客户端,使用标准浏览器作为客户端,其工作开发量较小。只需开发服务器端即可。另外由于其采用浏览器显示数据,因此移植性非常好,不受平台限制。如早期的偷菜游戏,在各个平台上都可以完美运行。
B/S模式的缺点也较明显。由于使用第三方浏览器,因此网络应用支持受限。另外,没有客户端放到对方主机上,缓存数据不尽如人意,从而传输数据量受到限制。应用的观感大打折扣。第三,必须与浏览器一样,采用标准http协议进行通信,协议选择不灵活。
因此在开发过程中,模式的选择由上述各自的特点决定。根据实际需求选择应用程序设计模式。
- 分层模型
- OSI七层模型
1. 物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。
2. 数据链路层:定义了如何让格式化数据以帧为单位进行传输,以及如何让控制对物理介质的访问。这一层通常还提供错误检测和纠正,以确保数据的可靠传输。如:串口通信中使用到的115200、8、N、1
3. 网络层:在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。Internet的发展使得从世界各站点访问信息的用户数大大增加,而网络层正是管理这种连接的层。
4. 传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP(传输控制协议,传输效率低,可靠性强,用于传输可靠性要求高,数据量大的数据),UDP(用户数据报协议,与TCP特性恰恰相反,用于传输可靠性要求不高,数据量小的数据,如QQ聊天数据就是通过这种方式传输的)。 主要是将从下层接收的数据进行分段和传输,到达目的地址后再进行重组。常常把这一层数据叫做段。
5. 会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求(设备之间需要互相认识可以是IP也可以是MAC或者是主机名)。
6. 表示层:可确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。例如,PC程序与另一台计算机进行通信,其中一台计算机使用扩展二一十进制交换码(EBCDIC),而另一台则使用美国信息交换标准码(ASCII)来表示相同的字符。如有必要,表示层会通过使用一种通格式来实现多种数据格式之间的转换。
7. 应用层:是最靠近用户的OSI层。这一层为用户的应用程序(例如电子邮件、文件传输和终端仿真)提供网络服务。
- TCP/IP四层模型
TCP/IP网络协议栈分为应用层(Application)、传输层(Transport)、网络层(Network)和链路层(Link)四层。
- 协议格式
- TCP协议
- 网络名词术语解析
- SOCKET编程
Socket本身有“插座”的意思,在Linux环境下,用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。
既然是文件,那么理所当然的,我们可以使用文件描述符引用套接字。与管道类似的,Linux系统将其封装成文件的目的是为了统一接口,使得读写套接字和读写文件的操作一致。区别是管道主要应用于本地进程间通信,而套接字多应用于网络进程间数据的传递。
套接字的内核实现较为复杂,不宜在学习初期深入学习。
在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socketpair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。
在网络通信中,套接字一定是成对出现的。一端的发送缓冲区对应对端的接收缓冲区。我们使用同一个文件描述符索发送缓冲区和接收缓冲区。
TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socket API。本章的主要内容是socket API,主要介绍TCP协议的函数接口,最后介绍UDP协议和UNIX Domain Socket的函数接口。
网络字节序
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。
IP地址转换函数
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
网络套接字函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
domain:
AF_INET 这是大多数用来产生socket的协议,使用TCP或UDP来传输,用IPv4的地址
AF_INET6 与上面类似,不过是来用IPv6的地址
AF_UNIX 本地协议,使用在Unix和Linux系统上,一般都是当客户端和服务器在同一台及其上的时候使用
type:
SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
SOCK_SEQPACKET该协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
SOCK_RAW socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序
protocol:
传0 表示使用默认协议。
返回值:
成功:返回指向新创建的socket的文件描述符,失败:返回-1,设置errno
#### 传智云盘项目
- 分布式存储FastDFS
- 缓存数据库redis
- 持久化数据库mysql
- HTTP协议
- Nginx
- FastCGI
- CGI
通用网关接口(Common Gateway Interface、CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。
CGI独立于任何语言的,CGI程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行。Unix shell script、Python、 Ruby、PHP、 perl、Tcl、 C/C++和 Visual Basic 都可以用来编写 CGI 程序。
最初,CGI 是在 1993 年由美国国家超级电脑应用中心(NCSA)为 NCSA HTTPd Web 服务器开发的。这个 Web 服务器使用了 UNIX shell 环境变量来保存从 Web 服务器传递出去的参数,然后生成一个运行 CGI 的独立的进程。
CGI处理流程
1. web服务器收到客户端(浏览器)的请求Http Request,启动CGI程序,并通过环境变量、标准输入传递数据
2. CGI进程启动解析器、加载配置(如业务相关配置)、连接其它服务器(如数据库服务器)、逻辑处理等
3. CGI进程将处理结果通过标准输出、标准错误,传递给web服务器
4. web服务器收到CGI返回的结果,构建Http Response返回给客户端,并杀死CGI进程
CGI使外部程序与Web服务器之间交互成为可能。CGI程序运行在独立的进程中,并对每个Web请求建立一个进程,这种方法非常容易实现,但效率很差,难以扩展。面对大量请求,进程的大量建立和消亡使操作系统性能大大下降。此外,由于地址空间无法共享,也限制了资源重用。
- FastCGI
快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关接口(CGI)的改进,描述了客户端和服务器程序之间传输数据的一种标准。
FastCGI致力于减少Web服务器与CGI程式之间互动的开销,从而使服务器可以同时处理更多的Web请求。与为每个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI进程管理器管理,而不是web服务器。
FastCGI处理流程
1. Web 服务器启动时载入初始化FastCGI执行环境。 例如IIS、ISAPI、apache mod_fastcgi、nginx ngx_http_fastcgi_module、lighttpd mod_fastcgi。
2. FastCGI进程管理器自身初始化,启动多个CGI解释器进程并等待来自Web服务器的连接。启动FastCGI进程时,可以配置以ip和UNIX 域socket两种方式启动。
3. 当客户端请求到达Web 服务器时,Web服务器将请求采用socket方式转发FastCGI主进程,FastCGI主进程选择并连接到一个CGI解释器。Web 服务器将CGI环境变量和标准输入发送到FastCGI子进程。
4. FastCGI子进程完成处理后将标准输出和错误信息从同一socket连接返回Web服务器。当FastCGI子进程关闭连接时,请求便处理完成。
5. FastCGI子进程接着等待并处理来自Web 服务器的下一个连接。
由于FastCGI程序并不需要不断的产生新进程,可以大大降低服务器的压力并且产生较高的应用效率。它的速度效率最少要比CGI 技术提高 5 倍以上。它还支持分布式的部署,即FastCGI 程序可以在web 服务器以外的主机上执行。
CGI 是所谓的短生存期应用程序,FastCGI 是所谓的长生存期应用程序。FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute 模式)。
进程管理器管理:spawn-fcgi
Nginx不能像Apache那样直接执行外部可执行程序,但Nginx可以作为代理服务器,将请求转发给后端服务器,这也是Nginx的主要作用之一。其中Nginx就支持FastCGI代理,接收客户端的请求,然后将请求转发给后端FastCGI进程。
由于FastCGI进程由FastCGI进程管理器管理,而不是Nginx。这样就需要一个FastCGI进程管理器,管理我们编写FastCGI程序。
spawn-fcgi是一个通用的FastCGI进程管理器,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目。
spawn-fcgi使用pre-fork 模型,功能主要是打开监听端口,绑定地址,然后fork-and-exec创建我们编写的FastCGI应用程序进程,退出完成工作。FastCGI应用程序初始化,然后进入死循环侦听socket的连接请求。
编译安装spawn-fcgi
1. tar -zxvf spawn-fcgi-1.6.4.tar.gz
2. cd spawn-fcgi-1.6.4/
3. ./configure
4. make
5. sudo make install
软件开发套件:fcgi
编译安装fcgi
1. tar -zxvf fcgi-2.4.1-SNAP-0910052249.tar.gz
2. cd fcgi-2.4.1-SNAP-0910052249/
3. ./configure
4. make
5. sudo make install
Nginx的fcgi的配置
- FastDFS的Nginx模块
一个好的分布式文件系统最好提供Nginx的模块,因为对于互联网应用来说,像文件这种静态资源,一般是通过HTTP的下载,此时通过容易扩展的Nginx来访问FastDFS,能够让文件的上传和下载变得特别简单。
Nginx安装FastDFS模块,主要是安装在FastDFS的存储服务器(storage)上,而不是tracker和client上。目的实际是为了,当输入地址(其中192.168.31.109 是一个storage服务器):http://192.168.31.109/group1/M00/00/00/wKgCbFem0l2ALSbFAAEYXfRAMkc536.png
能够通过Nginx的Web服务功能,直接返回图片。
- QT客户端编程
- 后台数据处理
STL基础教程
STL基础教程
- STL概论
- STL三大组件
- 常用容器
- string
- vector
vect(T) v; vector(v.begin(), v.end()); vector(n,elem); vector(const vector & vec);
assign(beg, end); assign(n, elem); vector& operater=(const vector & vec); swap(vec);
size() empty() resize(int num) capacity() reserve(int len)
at(int idx); operater[]; front(); back();
insert(const_iterator pos, int count,ele); push_back(ele); pop_back(); erase(const_iterator start, const_iterator end); erase(const_iterator pos); clear();
- deque
- 构造函数
deque<T> deqT;//默认构造形式
deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem);//构造函数将n个elem拷贝给本身。
deque(const deque &deq);//拷贝构造函数。
- 赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
deque& operator=(const deque &deq); //重载等号操作符
swap(deq);// 将deq与本身的元素互换
- 大小操作
deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除。
- 双端插入和删除操作
push_back(elem);//在容器尾部添加一个数据
push_front(elem);//在容器头部插入一个数据
pop_back();//删除容器最后一个数据
pop_front();//删除容器第一个数据
- 数据存取
at(idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range。
operator[];//返回索引idx所指的数据,如果idx越界,不抛出异常,直接出错。
front();//返回第一个数据。
back();//返回最后一个数据
- 插入操作
insert(pos,elem);//在pos位置插入一个elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
- 删除操作
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除pos位置的数据,返回下一个数据的位置。
- 构造函数
- stack
- queue
- list
- set/multiset
- map/multimap
- 常用算法
- STL综合案例