C + + learning diary
- Double colon scope operator
- Namespace namespace
- Using declaration and using compilation instructions
- The enhancement of c + + to c
- Memory allocation of const
- The difference between const and define
- Inline function
- extern
- explicit
- Singleton mode
- Up down type conversion
- Type conversion
- Static conversion_ cast)
- Dynamic transformation_ cast)
- Constant conversion (const_cast)
- reinterpret_cast)
- C + + exception
- Stack unwinding
- Abnormal interface declaration
- Life cycle of abnormal variable
- Abnormal polymorphic use
- System standard exception class
- C + + input and output streams
Double colon scope operator
:: scope operator, when there is no scope before::, it means to use global scope
#include<iostream> using namespace std; int a = 1000; int main() { int a = 2000; cout << "Local variable:" << a << endl; cout << "Global variable:" << ::a << endl; return 0; }
Namespace namespace
1. Resolve naming conflicts
2. Can store variables, functions, structs, classes
3. Namespace must be declared under global scope
4. Namespaces can be nested
5. Namespace is open. You can add new members to the namespace at any time, define the existing namespace, and merge
6. Namespace can be anonymous, which is equivalent to adding the keyword static before it
7. Namespace can be aliased
#include<iostream> using namespace std; // 2. Store variables, functions, etc namespace A { int m; void find(){} struct MyStruct { int n; }; } // 4. Namespaces can be nested namespace B { int m; namespace C { int n; } } // 5. Namespace is open, you can add new members to the namespace at any time namespace B { int c; } // 6. Namespace can be anonymous, which is equivalent to adding the keyword static before it namespace { int a = 100; int b = 200; } // 7. Namespace can be aliased namespace longname { int a; } void test01() { B::C::n = 10; cout << B::C::n << endl; } void test02() { B::c = 10; cout << B::c << endl; } void test03() { namespace shortname = longname; shortname::a = 10; cout << shortname::a << endl; } int main() { // 4. Namespaces can be nested test01(); // 5. Namespace is open, you can add new members to the namespace at any time test02(); // 7. Namespace can be aliased test03(); return 0; }
Using declaration and using compilation instructions
#include<iostream> using namespace std; namespace A { int m = 10; } void test01() { // using declaration using A::m; // If the principle of proximity appears, ambiguity should be avoided //int m = 20; //Cout < m < endl; / / error //Cout < A:: m < endl; / / error } void test02() { // using compilation instructions using namespace A; // In case of the principle of proximity, priority shall be given to the principle of proximity (partial) // If there are elements with the same name in more than one namespace, you need to indicate the scope int m = 20; cout << m << endl; cout << A::m << endl; } int main() { // using declaration test01(); // using compilation instructions test02(); return 0; }
The enhancement of c + + to c
1. Global variable detection enhancement
For example, the following code can be passed in C, but not in C + +
int a; int a = 10;
2. Function detection enhancements. Parameter variable type detection enhancement, function declaration return value detection enhancement, function return value detection enhancement, call parameter number detection enhancement
3. Type conversion detection enhancements
For example, the following code passes in C, not in C + +, and malloc returns void*
char *p = malloc(64);
Casts are required in C + +
char *p = (char *)malloc(64);
4. For struct enhancement, functions cannot be placed in the structure in C language, but in C + +; struct must be added in the declaration structure in C language, but not in C + +
5. Bool type is enhanced. There is no bool type in C language, but there is
6. Trinocular operator enhancement
Value is returned in C language, and variable is returned in C + +
For example, the following code cannot be run in C language, and can be used in C + +
int a = 10; int b = 20; a > b ? a : b = 100
7. const enhancements
In C language, the local const modifier variable can be modified (pointer) indirectly, but not globally. It cannot be used to initialize an array
In C + + language, the local const modifier variable can not be modified indirectly (pointer), nor can it be global. It can be used to initialize an array
When C + + uses pointer to modify local const variables, it is equivalent to having a temporary variable to store const variables, and the pointer is equal to the address of the temporary variable, not directly modified to const constant
const is an external (external document can be used) link attribute by default in C language. By default, extern is added before the global variable
In C + +, the default is internal (only this file) link attribute, which must be added manually
extern to improve scope
Memory allocation of const
1. When the address of the const decorated variable is taken, memory will be temporarily allocated
const int A = 10; int *p = (int *)&A;
2. After adding the extern keyword before const, memory will also be allocated
3. Use variables to initialize const decorated variables
int a; const int A = a; int *p = (int *)&A; *p = 20; // A becomes 20 cout << A << endl;
4. For custom data types, memory is also allocated
struct Person { string name; int age; }; int main() { const Person p; // It can not be modified directly, but can be modified indirectly Person *pp = (Person *)&p; pp->name = "Zhang San"; pp->age = 18; cout << pp->name << endl; cout << pp->age << endl; return 0; }
The difference between const and define
1. const has type, which can be used for compiler security check. ාdefine has no type, which cannot be used for type check
2. const has scope, but define does not pay attention to scope. The default definition is at the end of the file. If you define a valid constant under the specified scope, then define cannot be used
Inline function
Macro function defect:
1. To ensure the integrity of the operation, parentheses should be added
2. Parentheses were added in time, and some cases still did not meet the expected results
3. Ignore scope
#define Myadd(x, y) x+y int main() { int a = 10; int b = 20; cout << Myadd(a, b) << endl; // Output 30 cout << Myadd(a, b) * 100 << endl; // Output 210, expected 300 return 0; }
After parenthesis
#define Myadd(x, y) ((x)+(y)) int main() { int a = 10; int b = 20; cout << Myadd(a, b) << endl; // Output 30 cout << Myadd(a, b) * 100 << endl; // Output 300, expected 300 return 0; }
Problems that can't be solved with parentheses
#define Mycompare(x, y) (((a) > (b)) ? ((a) : (b))) int main() { int a = 10; int b = 20; cout << Mycompare(a, b) << endl; // Output 20 // Myadd(++a, b) ⇒ (((++a) > (b)) ? ((++a) : (b))) cout << Myadd(++a, b) << endl; // Output 12, expectation 11 return 0; }
inline has all the behaviors of ordinary functions, and will be expanded like predefined macros in appropriate places. Therefore, it does not need the cost of function calls, and can replace macro definitions
be careful:
1. The keyword inline must be added before declaration and definition, otherwise it will not be used as inline function
2. The inline keyword is added before the member function by default
The compiler does not inline a function if:
1. There cannot be any form of circular statement
2. There cannot be too many conditional statements
3. Function body cannot be too large
4. The function cannot be valued
extern
Purpose: C language files can be run in C + +
When using a function of an external file (C file), an unexpected error occurs because the name is decorated when C + + links
The solution is as follows:
1. Tell the compiler to link in C, not in C + +
extern "C" function name ();
2. Set in the external file (C file) with the following code
// Before the document header #ifdef __cplusplus extern "C" { #endif // Add at the end of the document #ifdef __cplusplus } #endif
For example:
#ifdef __cplusplus extern "C" { #endif #include <stdio.h> void show(); #ifdef __cplusplus } #endif
explicit
Purpose: to prevent implicit type conversion from initializing objects
class MyString { public: MyString(char *str) { } explicit MyString(int len) { } char *str; int len; } int main() { MyString s1 = "abc"; MyString s2 = 10; // error MyString s3(10); MyString s4 = MyString (20); return 0; }
Singleton mode
Only one instance can be created
class ChairMan { public: // Data is shared, and only one object pointer is allowed // Return pointer static ChairMan* getInstance() { return this->singleMan; } private: // Constructor privatization ChairMan(){}; // Prevent copy construction and privatize copy construction ChairMan(const ChairMan &c){}; private: // Prevent external modification of pointer, set to private static ChairMan * singleMan; } ChairMan* ChairMan::singleMan = new ChairMan;
Up down type conversion
Space size: subclass > = parent
// Down conversion, parent rotor, unsafe Animal *animal = NULL; Cat * cat = (Cat *) animal;
// Upcast, child to parent, safe Cat *cat = NULL; Animal * animal = (Animal *) cat;
Note: if polymorphism occurs, it is always safe
Type conversion
Static conversion_ cast)
1. Used for conversion of pointer or reference between base class (parent class) and derived class (child class) in class hierarchy
It is safe to perform an uplink conversion (convert the pointer or reference of a derived class to the base class representation), child ----- > parent
When performing a downstream conversion (converting a pointer or reference of a base class to a derived class representation), it is not safe because there is no dynamic type checking. Parent ----- > child
2. Used for conversion between basic data types, such as int and char. The security of this transformation also needs to be guaranteed by the developers
#include<iostream> using namespace std; // 1. Static type conversion void test01() { // Built in data type char a = 'a'; // static_ Cast < target type > (original object) double d = static_cast<double>(a); cout << d << endl; } class Base{}; class Son:public Base{}; class Other{}; void test02() { // Custom data type Base *b = NULL; Son *s = NULL; // Base conversion to Son * type, down conversion is not safe Son *s2 = static_cast<Son*>(b); // success // Son to Base * type, up type safe Base *b2 = static_cast<Base*>(s); // success // base to other * type // Conversion between two types without parent-child relationship is not successful Ohter *o = static_cast<Other*>(b); // Error, unsuccessful }
Dynamic transformation_ cast)
1,dynamic_cast is mainly used for up conversion and down conversion between class levels
2. When the class level is up converted, dynamic_cast and static_ The effect of cast is the same
3. When performing downlink conversion, dynamic_cast has the function of type checking, which is better than static_ More secure cast
4. Any conversion with problems is not supported. For example, the precision of double to int is missing, and the conversion of built-in data type is not supported
#include<iostream> using namespace std; // 2. Dynamic type conversion class Base{}; class Son:public Base{}; class Other{}; class Animal { virtual void func(){}; }; class cat:public Animal { void func(){}; } void test02() { // Custom data type Base *b = NULL; Son *s = NULL; // Base conversion to Son * type, down conversion is not safe Son *s2 = dynamic_cast<Son*>(b); // Error, unsuccessful // Son to Base * type, up type safe Base *b2 = dynamic_cast<Base*>(s); // success // base to other * type // Conversion between two types without parent-child relationship is not successful Ohter *o = dynamic_cast<Other*>(b); // Error, unsuccessful // If polymorphism occurs, the transition between father and son is always safe Animal *a = new Cat; // Animal to Cat * type, down type Cat *c2 = dynamic_cast<Cat*>(a); // success }
Constant conversion (const_cast)
This operator is used to modify const property of type, const from nothing to have, from have to no
1. Constant pointers are converted to non constant pointers and still point to the original object
2. Constant references are converted to non constant references and still point to the original object
Note: const cannot be used directly for non pointer and non reference variables_ Cast operator to remove its const directly
// Constant pointer is converted to non constant pointer void test01() { const int *p = NULL; int *p = const_cast<int*>(p); int *pp = NULL; const int *npp = const_cast<const int*>(pp); const int a = 10; int b = const_cast<int>(a); // Error, cannot convert non pointer or reference }
reinterpret_cast)
1. The most insecure transformation mechanism, most likely to have problems
2. It is mainly used to convert one data type from one data type to another. It can convert a pointer to an integer or an integer to a pointer
C + + exception
Error handling in C language: 1. Use integer return value to identify the error; 2. Use errno macro (which can be simply understood as a global variable) to record the error
throw exception in C + +, try to catch exception, catch catch exception
Note: the exception thrown by throw must be caught. If the exception is thrown and there is no matching type catch in catch, the terminate function will be run, and its default function is abort to terminate the program
You can also use custom type exceptions
#include<iostream> using namespace std; class MyException { public: void print() { cout << "My own extraordinary mistake" << endl; } }; int MyDiv(int a, int b) { if (b == 0) { //throw 1; //throw 3.14; //throw 'a'; throw MyException(); // Throw anonymous object } return a / b; } void test01() { int a = 10, b = 0; try { MyDiv(a, b); } catch (int) { cout << "test01 Middle throw int Exception of type" << endl; } catch (double) { cout << "test01 Middle throw double Exception of type" << endl; } catch(MyException e) { e.print(); } catch (...) { // Do not handle exceptions thrown up throw; cout << "test01 Other types of exceptions are thrown in" << endl; } } int main() { try { test01(); } catch (int) { cout << "main Middle throw int Exception of type" << endl; } catch (double) { cout << "main Middle throw double Exception of type" << endl; } catch (...) { cout << "main Other types of exceptions are thrown in" << endl; } return 0; }
Stack unwinding
From the start of try code to throw exception, all objects on the stack are released in the reverse order of release and construction
Abnormal interface declaration
1. In order to enhance the readability of the program, you can list all types that may throw exceptions in the function declaration, such as: void func() throw(A,B,C); this function func can and can only throw exceptions of types A,B,C and their subtypes
2. If there is no exception interface declaration in the function declaration, this function can throw any type of exception, for example: void func();
3. A function that does not throw any type of exception can be declared as: void func() throw();
4. If a function runs out of an exception that is not allowed to be thrown by its exception interface declaration, the unexpected function will be called. The default behavior of the function is to call the terminate function to interrupt the program
Life cycle of abnormal variable
class MyException { public: MyException() { cout << "MyException Constructor" << endl; } MyException(const MyException& e) { cout << "MyException Copy construct call" << endl; } ~MyException() { cout << "MyException Destructor" << endl; } }; void doWork() { throw MyException(); } void test01() { try { doWork(); } // MyException e calls the copy constructor // MyException *e, receive with pointer, throw & myexception(); anonymous object, object is released, can no longer operate e // You can also throw a new MyException() to receive it with a pointer, but you need to release it manually // Myexception & E, so receive by reference catch (MyException &e) { cout << "MyException Exception capture for" << endl; } } int main() { test01(); return 0; }
Abnormal polymorphic use
// Exception base class class BaseException { public: virtual void printError() = 0; }; // Null pointer exception class class NullPointException:public BaseException { public: virtual void printError() { cout << "Null pointer exception" << endl; } }; // Cross boundary anomaly class OutOfRangeException:public BaseException { public: virtual void printError() { cout << "Cross boundary anomaly" << endl; } }; void doWork() { throw NullPointException(); } void test01() { try { doWork(); } catch(BaseException &e) { e.printError(); } }
System standard exception class
Members of the standard exception class:
1. In the above inheritance system, each class provides constructor, copy constructor and assignment operator overload
2,logic_error class and its subclass, runtime_ The error class and its subclasses, whose constructors accept a formal parameter of string type for the description of exception information
3. All exception classes have a what() method that returns the value of const char * type (C-style string), describing the exception information
Specific description of standard exception class:
Exception name | describe |
---|---|
exception | Parent of all standard exception classes |
bad_alloc | When the request to allocate memory fails when operator new and operator new [] |
bad_exception | This is a special exception, if bad is declared in the function's exception throw list_ Exception exception: when an exception is thrown inside a function, an exception that is not in the list will be thrown. This is an unexpected function called. If an exception is thrown, no matter what type, it will be replaced with bad_exception type |
bad_typeid | Use the typeid operator to operate on a NULL pointer, which is a class with a virtual function, and then throw bad_typeid exception |
bad_cast | Using dynamic_ When the cast conversion reference fails |
ios_base::failure | Error in io operation |
logic_error | Logical errors, errors that can be detected before running |
runtime_error | Runtime errors, errors that can only be detected at runtime |
logic_ Subclass of error:
Exception name | describe |
---|---|
length_error | When trying to generate an object that exceeds the maximum length of the type, such as the resize operation of vector |
domain_error | The value range of the parameter is wrong, which is mainly used in mathematical functions. For example, using a negative value to call a function that can only operate on non negative numbers |
out_of_range | Out of valid range |
invaild_argument | Parameter is not appropriate. In the standard library, this exception is thrown when bitset is constructed with string object and the character in string is not '0' or '1' |
runtime_ Subclass of error:
Exception name | describe |
---|---|
range_error | The calculation results are beyond the range of meaningful values |
overflow_error | Arithmetic overflow |
underflow_error | Arithmetic underflow |
invaild_argument | Parameter is not appropriate. In the standard library, this exception is thrown when bitset is constructed with string object and the character in string is not '0' or '1' |
For example:
#include<iostream> using namespace std; #include<stdexcept> void doWork(int age) { if (age < 0 || age > 150) { throw out_of_range("Age crossing"); } } void test01() { int a = 151; try { doWork(a); } catch (exception &e) { cout << e.what() << endl; } } int main() { test01(); return 0; }
C + + input and output streams
Standard input stream
cin.get() // Read only one character at a time test01() cin.get() // Pass in a parameter cin.get() // Passing in two parameters does not take the newline test02() cin.getline() // Passing in two parameters, taking the newline, but throwing away the newline test03() cin.ignore() // There are two kinds of test04() test05() without parameters cin.peek() // Peep back to est06() cin.putback() // Put back test07()
void test01() { // Enter a s \ n, a s in the buffer will wrap, the first will take a, the second will take s, the third will take a new line, and the fourth will wait for the next input char c = cin.get(); cout << "c = " << c << endl; c = cin.get(); cout << "c = " << c << endl; c = cin.get(); cout << "c = " << c << endl; c = cin.get(); cout << "c = " << c << endl; } void test02() { char buf[1024]; cin.get(buf, 1024); char c = cin.get(); if (c = '\n') { cout << "Line feed still in buffer" << endl; } else { cout << "Line feed not in buffer" << endl; } } void test03() { char buf[1024]; cin.getline(buf, 1024); char c = cin.get(); if (c = '\n') { cout << "Line feed still in buffer" << endl; } else { cout << "Line feed not in buffer" << endl; } } void test04() { // Enter as\n cin.ignore(); // No parameter means one character is ignored char c = cin.get(); // Output s cout << "c = " << c << endl; } void test05() { // Enter as\n cin.ignore(2); // With parameter n, n characters are ignored char c = cin.get(); // Output \ n cout << "c = " << c << endl; } void test06() { // Enter as\n // Take a peek at a and put it back in the buffer, which is still as\n char c = cin.peek(); // Output a cout << "c = " << c << endl; c = cin.get(); // Output a cout << "c = " << c << endl; } void test07() { // Type hello world\n char c = cin.get(); cin.putback(c); // Take it up, putback char buf[1024]; cin.getline(buf, 1024); // Output hello world\n cout << buf << endl; }
Standard output stream
Character output
cout.flush() // Refresh buffer, effective under linux cout.put() // Write characters to buffer cout.write() // Write num bytes from buf to current output stream
void test() { // Output single character a cout.put('a'); // Output character bc cout.put('b').put('c'); char buf[] = "hello world"; // Output hello world cout.write(buf, strlen(buf)); }
Format output
(not summarized yet)