Article directory
- Separation of implementation and declaration
- Do not use using namespace std;
- The enhancement of C + + to C language
- Key 1 references
- Member function call const to decorate object instance
- Construction and destructor instances
- Deep copy shallow copy
- Initialization list
- The case of class objects as class members
- explicit keyword
- new dynamic object creation perfectly replaces malloc
- Static member variable
- Singleton mode
- Member variables and member properties are handled separately
- this pointer
- Function of null pointer access member
- Constant function and constant object
- Global function as friend function
- Whole class as friend class
- Let member function be friend function
- Operator overloading
- Two yuan overloading
- Attention points of heavy load moving left and right
- Pre post increment operator
- Pointer operator overload (customize a smart pointer)
- Assignment operator overload
- Overload of [] operator
- Relational operator overload
- Function call operator overload
- Do not overload|and&&
- Custom string class
- inherit
- Inheritance mode
- Object model in inheritance
- Construction and deconstruction order in inheritance
- Processing of members with the same name in inheritance
- Handling of static members in inheritance
- Multiple inheritance
- diamond inheritance
- How virtual inheritance works
- polymorphic
- Static and dynamic editing
- Analysis of polymorphism principle
- Polymorphic case 1 calculator
- Abstract class and pure virtual base class
- Virtual and pure virtual destructors
- Upcast downcast
- Game polymorphism instance
- Template
- Sorting example
- The difference between ordinary function and function template
- Internal principle of template mechanism
- Limitation of function template
- Use of class templates
- When to create a member function
- Class template as function parameter
- Inheritance of class template
- Implement member function outside class template
- Class template file code
- Friend function of class template
- The application of class template write a general array class
- C + + type conversion
- Static type conversion
- Dynamic type conversion
- Constant conversion
- Reinterpret transformation (useless)
- abnormal
- The basic use of exceptions in C + +
- Custom exception class
- Stack unwinding
- Abnormal interface declaration
- Life cycle of abnormal variable
- Abnormal polymorphic use
- System standard exception
- Implement an exception class by yourself
- I / O stream
Separation of implementation and declaration
The header file with the same name is referenced in the source file. The header file is only declared and defined in the source file
For example, a game1.cpp #include, a game1.h, and then calling game1.h in main.cpp, you can use the functions defined in game1.cpp, which is the separation of implementation and declaration.
Do not use using namespace std;
Replace with std::
The enhancement of C + + to C language
Various detection enhancements, such as type conversion enhancements
Using struct in C + + can eliminate the need to write struct
There is no bool type in C language, and there is
The enhancement of three visual operators in C + +
a>b? a:b;
Because C + + finally returns variables, the last operation above is b=100
const is a real constant in C + +, which does not allocate memory and is placed in the symbol table;
In C + +, address modification is used, only to modify the value in the temporary space
In C, const is a pseudo constant that can be modified by address, and the compiler allocates memory
Key 1 references
(1) Reference basic syntax type & alias = original name
(2) Reference must be initialized reference initialization cannot be modified
(3) Create a reference to an array
int arr[10]; //Alias array int(&pArr)[10]=arr; cout<<pArr[i]<<endl;
(4) Reference passing
void mySwap3(int &a,int &b) { } mySwap2(&a,&b);
Notes for reference
1. The reference must refer to a legal memory space
2. Do not return a reference to a local variable
int &a=10;//The reference must refer to a piece of legal memory space, which will report an error
Note that if the return value of a function is a reference, the function call can be used as an lvalue
The nature of quotation
ref=100;//This step of ref conversion is implicitly completed by C + +
Pointer reference
Using pointers to create space for the same purpose but without * * this operation
First level pointer reference can be used instead of second level pointer
Constant reference
In fact, constant references can also be modified
Constant reference scenario 1:
Member function call const to decorate object instance
Add 'const' after the function to make it clear that this member function will not modify the const object, otherwise the regular member function cannot call the const object because the compiler does not know whether the member function has modified it.
Construction and destructor instances
Construction and deconstruction must be under public
Cannot overload without parameters
Note that when we provide a constructor with parameters, the system will no longer provide a default constructor, but the default copy and destruct are still available
copy constructor
The reason to use the reference form is that if you do not use the reference, you will have a dead cycle to pass values, and then you will call the copy structure
The second way to call is copy construction
When to call copy constructor
Deep copy shallow copy
class Person { Person(){} Person(char * name, int age){ //m_Name=name;//char * better on the heap m_Name=(char *)molloc(strlen(name)+1);//The composition of content on the heap cannot be manually free by default strcpy(m_Name,name); m_age=age; } char * m_Name; int m_age; //If the copy structure is used by default, an error will be reported ~Person(){ if(m_Name!=NULL) { free(m_Name); m_Name=NULL;//Prevent wild pointer } } };
In this way, the sub call copy structure will report an error
Wrong reasons
After the mName of p1 is released, the mName of p2 is also released again, but at this time, the address is empty, so an error is reported.
This simple copy of the address is called a shallow copy
Deep copy
Create a new space by yourself. You can't use the system's default copy structure
Initialization list
perhaps
The case of class objects as class members
explicit keyword
class Mystring{ public: Mystring(const char *str) { } explicit Mystring(int a)//This line of keywords is to prevent implicit type conversion { msize=a; } char * mstr; int msize; }; void test() { Mystring str="mystring"; Mystring str3(10);//That's right. It's obvious that there is a parameter construction in the call to int type Mystring str2=12;//Ambiguous code usage is not clear str2 string is' 10 ', string length is 10 do not know which parameter structure is called //An implicit type cast is raised // In this case, adding an explicit line of code will result in an error }
Implicit conversion refers to the type conversion behavior of compiler without user intervention. Most of the time, users may not know what transformations have been made.
The principle of C + + implicit conversion
The conversion of basic data type is based on the value range (to ensure the accuracy is not lost).
Implicit conversions occur in small to large conversions. For example, convert from char to int.
From int - 'long.
Custom object subclass objects can be implicitly converted to parent objects.
**s4 and s5 implicitly convert an int type and a char type to an empty string with several bytes allocated**
new dynamic object creation perfectly replaces malloc
Original malloc operation
Existing problems
One line solution
Person person= new Person;//Auto call constructor
class Person2{ public: Person2() {} //copy construction ~Person2() {} }; void test2(){ //Person2 person; stack area development Person2 *p2=new Person2;//When the reactor area is opened, it will not release automatically //All new pairs will return pointers of this type //malloc doesn't call construction automatically, but here new calls construction automatically. New is an operator. malloc is a function //delete is required to free heap space delete p2;//delete is also an operator to be used with a new one. Don't confuse it with free malloc }; void test3() { void *p2=new Person2;//When using void * to accept the new pointer, there will be a release problem delete p2;//Will not be released to avoid this writing } void test4() { //Open an array through new. Be sure to provide a default constructor. Write your own structure and then write a default constructor Person2 * pArray=new Person2[10]; //When an array is opened on the stack, it can be specified that there must be a default stack to construct the heap area //Person2 pArray[10]={Person2(1),Person2(2)}; delete [] pArray;//When the array must be released with brackets }
If there is no bracket delete, you will not know the array size record. 3, you will not know how many times to call destruct
Static member variable
class Person2{ public: Person2() {} static int m_Age;//Adding static means that static member variables will share data //Static member variable, declared in class, initialized outside class ~Person2() {} private: static int m_other;//Private permission cannot be accessed outside the class but can be initialized }; int Person2::m_Age=10;//Out of class initialization implementation int Person2::m_other=10;//Using Person:: is equivalent to within the class
Static member function
class Person2{ public: Person2() {} static int m_Age;//Adding static means that static member variables will share data int m_time; //Static member variable, declared in class, initialized outside class ~Person2() {} static void func()//You can't access a common member variable. You can't tell who passed this common member variable { m_time=15;//error m_Age=10;//Static member variables can be accessed correctly cout<<"func call"<<endl; } private: static int m_other;//Private permission cannot be accessed outside the class but can be initialized };
Reason
Static member variables can be accessed
Static member functions are also private and non class access with permission
Singleton mode
For example, the task manager of the system, as an object, has only one window no matter how it is opened by right clicking. No matter how it is created by right clicking, it is the same object. If only one object can be instantiated in a class, it is called singleton mode
For example, the chairman class can only have one new chairman object
//Create chairman class //In order to create objects in a class and ensure that there is only one object instance class ChairMan { private://Constructor privatization ChairMan() {} public: static ChairMan *singlemen;//Inner class declaration does not need to get this chairman through object }; ChairMan * ChairMan::singlemen=new ChairMan;//Namespace allows access to private constructors void test11() { // ChairMan c1; // ChairMan * c2= new ChairMan; //No matter how many objects are created, they are the same chairman ChairMan *cm=ChairMan::singlemen;//This ensures that there is only one chairman and that the creation is completed during the compilation process. The object is created before main runs ChairMan *cm2=ChairMan::singlemen;//This ensures that there is only one chairman and that the creation is completed during the compilation process. The object is created before main runs //In order to prevent the staff from changing the chairman, for example ChairMan::singlemen=NULL; //All singleMan properties need to be set as private external interfaces for access }
After all properties are privatized
//Create chairman class //In order to create objects in a class and ensure that there is only one object instance class ChairMan { private://Constructor privatization ChairMan() {} private: static ChairMan *singlemen;//Inner class declaration does not need to get this chairman through object public: static ChairMan * getinstance() { return singlemen; } }; ChairMan * ChairMan::singlemen=new ChairMan;//Namespace allows access to private constructors void test11() { // ChairMan c1; // ChairMan * c2= new ChairMan; //No matter how many objects are created, they are the same chairman //ChairMan *cm=ChairMan::singlemen; / / this ensures that there is only one chairman and that the object is created before the compilation process is completed and main runs //ChairMan *cm2=ChairMan::singlemen; / / this ensures that there is only one chairman and that the object is created before the compilation process is completed and main runs ////In order to prevent the staff from changing the chairman, for example //ChairMan::singlemen=NULL; //All singleMan properties need to be set as private external interfaces for access ChairMan* cm1=ChairMan::getinstance(); }
Copy construction special case
There are two objects when cm2 and cm3 are different
So we need to privatize the copy constructor
Member variables and member properties are handled separately
Distinguish member functions by this pointer
The size of an empty class is 1
At this point, class object size equal to 4 is not the 8 as expected (function pointer 4 + member variable 4)
Reason:
Because non static member functions will be placed in another place, not in class objects
Similarly, static variables do not belong to class objects
The class object under byte alignment problem is not 12 but 16
Add a sentence
#pragma pack() affects alignment
this pointer
The compiler will secretly add a this pointer parameter to the member function to save the address of this object
At this point, the address of p1p2 is passed in
Point to whoever calls
On the left is normal code and on the right is compiler converted code
Use of this pointer
! [insert picture description here] (https://img-blog.csdnimg.cn/20200220160824632.png? X-oss-process = image / watermark, type ﹐ zmfuz3pozw5nagvpdgk, shadow ﹐ 10, text ﹐ ahr0chm6ly9ibg9nlmnzg4ubmv0l3dlaxhpbl8zotu1odiynw = =, size ﹐ 16, color ﹐ ffff, t ﹐ 70) Another example is! [insert picture description here] (https://img-blog.csdnimg.cn/20200220160927809.png? X-oss-process = image / watermark, type ﹣ zmfuz3pozw5nagvpdgk, shadow ﹣ 10, text ﹣ ahr0chm6ly9ibg9nlmnzzg4ubmv0l3dlaxhpbl8zotu1odiynw =, size ﹣ 16, color ﹣ ffff, t ﹣ 70) Without this, it's OK. age is this.age
Age addition example
If it is called as follows, an error will be reported
Because the return value is a void
Note here that if you want the return value to be an lvalue (so you can use the function call of the above form as lvalue), the return value needs to be a reference type
*
The above is the correct way to write. The return is still p1
p1.PlusAge(p2) still returns a p1
Note that references must be returned here
Function of null pointer access member
If the member function does not use this, the null pointer can be accessed directly
Prevent null pointer from accessing member functions (if this pointer is used, null pointer cannot be used)
Constant function and constant object
const decorated member function
Pointer cannot be modified
For example, this cannot be null;
But the value that the pointer points to can be modified
In order to make the value pointed to by this pointer cannot be modified, the implementation is similar to const Person * const this
If you insist on Revising
Use mutable keyword
const Person p2;
A constant object cannot call a normal member function. Because properties may be modified in a normal member function, const is added after the constant function
Global function as friend function
When a friend can access a private property class declaration, add a friend before it
The definition of the external global function can access the private content
Whole class as friend class
Write the class declaration first to let the compiler know
To make good friends visit bedrooms, we need to change them into good friends
Note that the keyword class cannot be missing
Let member function be friend function
Let a single function be a friend instead of the whole class
Just add a friend statement at the front
Custom array instance
myarray.h myarray.cpp main.cpp required
The first is the class declaration in myarray.h
// // Created by user1 on 2020/2/21. // #include <iostream> #pragma once using namespace std; #ifndef UNTITLED_MYARRAY_H #define UNTITLED_MYARRAY_H class myarray{ public: //Non parametric structure myarray();//Default 100 capacity //User specified capacity initialization with parameters explicit myarray(int capacity); //copy construction myarray(const myarray& array); //User operation interface //Add elements by location void SetData(int pos,int val); //Get location data int GetData(int pos); // Tail insertion method void PushBack(int val); //Get length int GetLength(); //Get capacity int getCapacity(); //Destructors, freeing array space ~ myarray(); private: int mCapacity;//How many elements can an array hold must be greater than mSize int mSize;//How many elements are there currently int *pAddredd;//Point to the space where data is stored }; #endif //UNTITLED_MYARRAY_H
Then there's the definition of the class
In myarray.cpp
// // Created by user1 on 2020/2/21. // #include <iostream> #pragma once using namespace std; #include "myarray.h" myarray::myarray() { this->mCapacity=100; this->mSize=0; this->pAddredd=new int [this->mCapacity];//Create an array } myarray::myarray(const myarray &array) { this->pAddredd=new int[array.mCapacity];//You can't use the address of array to assign values here, or you will have the problem of decomposing the same object twice this->mSize=array.mSize; this->mCapacity=array.mCapacity; //Copy the data after the size is consistent for(int i=0;i<array.mSize;i++) { this->pAddredd[i]=array.pAddredd[i]; } } //Provide array capacity myarray::myarray(int capacity) { this->mCapacity=capacity; this->mSize=0; this->pAddredd=new int [this->mCapacity];//Create an array } myarray::~myarray() { if (this->pAddredd != NULL) { delete[] this->pAddredd; } } void myarray::PushBack(int val) { //Need to judge the cross-border problem? Handle by users themselves this->pAddredd[this->mSize]=val; this->mSize++; } int myarray::GetData(int pos) { } void myarray::SetData(int pos, int val) { this->pAddredd[pos]=val; } int myarray::GetLength() { return this->mCapacity; } int myarray::getCapacity() { return this->mSize; }
Finally, the call and class initialization of main
void test01() { //Heap create array myarray *array=new myarray(30); //It's important myarray * arr2=new myarray(*array);//This is the new way to make the call copy construction. 1 myarray arr3=*arr2;//The ontology returned by the constructor is also called copy construction mode 2 myarray *array2=array;//This form does not call copy construction, but declares that a pointer is the same as the address of array execution, so copy construction will not be called for(int i=0;i<10;i++) { array2->PushBack(i); } for(int i=0;i<10;i++) { cout<<array2->GetData(i)<<endl; } delete array; cout<<arr2->getCapacity()<<endl; cout<<arr2->GetLength()<<endl; //If we want to get the contents of the set array, it is more intuitive //cout<<array[20]<<endl; //array2[0]=1000; //You need to overload operators } int main() { test01(); }
If we want to get the contents of the set array, it is more intuitive cout<<array[20]<<endl; array2[0]=1000; You need to overload operators
Details about copy construction initialization
Operator overloading
Member function writing
Global function writing
Two yuan overloading
In terms of the whole situation, a few variables, a few parameters, a few variables
Attention points of heavy load moving left and right
At this time, you cannot use cout < call to modify the return value
Use friend to overload after property is private
Pre post increment operator
class myint { public: myint(){}; myint(int a){ this->ma=a; } //No need to add in the pre + + overload parameter myint& operator++() { this->ma++; return *this; }; //Post + + myint& operator++(int){// This is a fixed collocation of pre and post //Save the previous data first myint tmp=*this; ma++; return tmp; }; friend ostream & operator<<(ostream &cout,myint &p1); private: int ma; }; ostream & operator<<(ostream &cout, myint &p1) { cout<<p1.ma<<endl; return cout; } void test6() { myint p1; //Cout < < P1 + + < endl; there are two overloads that need to be reloaded: one is a right shift overload and the other is a self-added overload cout<< ++p1<<endl;//The overload return value of self adding needs to be itself cout<< p1++<<endl;//Post + + }
That's why the front end is more efficient than the back end
Reasons for the difference between the pre and post return values:
The first example output is 2
When the return value of the preceding + + is changed to a reference
2,1 returned
In order to ensure that the pre + + ontology will be 2 after returning, the result of the first operation is its ontology rather than a temporary variable, so reference is used.
The post data returns a temporary value. The temporary data return reference may have an error
Pointer operator overload (customize a smart pointer)
To host pointer objects, delete without display
Maintain this pointer
The writing method of new person should also be changed
Explain that the constructor of the sp object in the above code is a construction with parameters
The maintained pointer is from the Person object of new
sp object is opened to the stack and will be released automatically
So the intelligent delete operation can be put into the analysis of this intelligent pointer, regardless of the analysis of the official Person
Overload *
Assignment operator overload
Situation 2:
Open up dynamic memory
(after adding the destruct) an error will occur at this time
The equal sign operator will simply pass the pname of p1 and p2 to the same object, which will be repeatedly destructed and crash.
You need to overload the equal sign operator
Create a new space in it again and again
Treatment of continuous equal signs in special cases
The original p2==p1 return value is void
Modify return value
To return a reference
Overload of [] operator
The above implementation returns a value that cannot be left, so an error will be reported
Relational operator overload
To do this
Implement unequal sign
Function call operator overload
To construct the imitative function for the overloaded bracket
Such as this form
Do not overload|and&&
Short circuit characteristics may be lost after heavy load
Custom string class
Heavy load of cin
Two equal sign overloads
And Deconstruction
Heavy load
String splicing
It's also two versions
Overloading of relational operators
inherit
Can have all properties of basepage
Inheritance mode
It is impossible for subclasses to inherit from private to public
If the parent class is private, it will always be private, but the public in the parent class can be made private by changing the inheritance method
Object model in inheritance
Use the following tools to display the inheritance structure
The son in the input is the class name, which file does the layout of a single class test.cpp belong to for the file path operation
cl /d1 reportSingleClassLayoutSon test.cpp
Construction and deconstruction order in inheritance
=, construction, deconstruction cannot be inherited
Processing of members with the same name in inheritance
Proximity principle
If you want to call the scope of the parent class plus a member
Must be explicitly stated
Handling of static members in inheritance
If there is any in the subclass parent, it is also the nearest principle or explicit call
Son::func() / / call to static member function
Multiple inheritance
The two fathers have members of the same name
Solution 1 namespace
diamond inheritance
The solution to ambiguity
Waste of resources
The solution to diamond inheritance is called virtual inheritance
Graph after virtual inheritance
It can be seen that M age only appears once and there is more virtual pointer vbptr
The virtual base class pointer points to the virtual base class table
There are offsets in the virtual base class table
Virtual table is an array offset is 8
0 + 8 = 8 find the m-age 4 + 4 = 8 find the m-age, so as long as one copy of the m-age storage data is not wasted
Now there is no ambiguity that can be accessed directly
How virtual inheritance works
(1) Offset finding operation
1. & St get object address first
2. (int *) & strong conversion to int type for subsequent step change operation
3. * (int *) & the real virtual table can be obtained only after the star fetching operation
4. (int * * (int *) & St + 1 change type to change step size after finding virtual table
5. After changing the step size, continue int conversion type and then take * to get the real 8. Find the offset and complete the operation
(2) Operation to get M age
1.
2. Add the previous offset after changing the type
3. At this time, change the type to an animal type
4. Then wrap it up as a whole
And found it.
polymorphic
A reference or pointer to a parent class points to a child class object
Static and dynamic editing
class Animal{ public: void speak(){ cout<<"animal talking"; } }; class Cat:public Animal{ public: void speak() { cout<<"cat talking"; } }; void dospeak(Animal & ani) { ani.speak(); } void test1(){ Cat cat; dospeak(cat); }
The above is an example of static orchestration
The output of the animal class, which has been bound since the compilation stage, is' animal talking '
If you want the anchor to talk, you can't bind the address of the function in advance. You need to determine the address of the function at runtime
This is called dynamic binding
Change the speak in the parent class to a virtual function
} class Animal{ public: void virtual speak(){//Add a virtual here cout<<"animal talking"; } }; class Cat:public Animal{ public: void speak() { cout<<"cat talking"; } }; void dospeak(Animal & ani) { ani.speak(); } void test1(){ Cat cat; dospeak(cat); }
At this time, the output is "cat talking", and dynamic polymorphism occurs
At this time, the reference of the Animal &animal=cat parent class points to the child class object
Analysis of polymorphism principle
Without virtual
class Animal{ public: void speak(){ cout<<"animal talking"; } }; class Cat:public Animal{ public: void speak() { cout<<"cat talking"; } }; void dospeak(Animal & ani) { ani.speak(); } void test1(){ Cat cat; dospeak(cat); } void test3() { Animal an1; cout<< sizeof(Animal)<<endl; }
Animal at this time, the size is 1 empty class
If you add virtual
The output will be 4, and the Animal class has changed
Class contains a virtual pointer inside
Points to the address of the animal intrinsic function
cat inherits but does not write speak
Inherit virtual pointer and virtual table and change the direction of virtual pointer at the same time
After rewriting speak
Override must return the same value parameters
Replace the contents of the virtual table of the parent class
When a parent class pointer or a child class object is used, speak in virtual table cat is called
Polymorphic case 1 calculator
The original state only has addition and subtraction
#include <iostream> using namespace std; class Calculator{ public: Calculator(){}; void setv1(int v){ this->val1=v; }; void setv2(int v){ this->val2=v; }; int get_result(string oper){ if (oper=="+") { return val1+val2; } else if (oper=="-"){ return val1-val2; } }; int val1; int val2; }; void test1() { Calculator ca1; ca1.setv1(10); ca1.setv2(10); cout<<ca1.get_result("+"); } int main() { test1(); return 0; }
Then add multiplication and division
At this time, we need to use polymorphism to achieve
class Calculatorbase{ public: int virtual get_result(){ return 0; }; void setv1(int v){ this->val1=v; }; void setv2(int v){ this->val2=v; }; int val1; int val2; }; //Addition calculator class Calculatorplus:public Calculatorbase{ public: int get_result(){ return val1+val2; }; }; //Subtraction calculator class Calculatorsub:public Calculatorbase{ public: int get_result(){ return val1-val2; } }; void test4() { Calculatorbase * abc=new Calculatorplus;//It is declared that the polymorphic parent class of an addition calculator points to the child class abc->setv1(10); abc->setv2(12); cout<<abc->get_result()<<endl; } int main() { test4(); return 0; }
At this time, to add a new function, you do not need to change the original code, just add the subclass code of the new function
Abstract class and pure virtual base class
We find that the get result in the parent class has no meaning, so we need to modify it at this time
Delete all unnecessary function implementations and change them into pure virtual functions
1. If there is pure virtual function in the parent class, the child class must implement this pure virtual function to inherit the parent class
2. If there is a pure virtual function parent in the parent class, it cannot be instantiated
3. This class has a pure virtual function, also called abstract class
Virtual and pure virtual destructors
Original version
class Animal{ public: void virtual speak() { cout<<"animal talking"; } ~Animal(){ cout<<"animal ~"; } }; class Cat:public Animal{ public: Cat(const char * name) { this->m_Name=new char[strlen(name)+1]; strcpy(this->m_Name,name); } void virtual speak() { cout<<"cat talking"; } char * m_Name;//Name ~Cat(){ cout<<"cat ~"<<endl; if (this->m_Name!=NULL) { delete [] this->m_Name; this->m_Name=NULL; } } }; void test5() { Animal * animal=new Cat("TOM"); animal->speak(); delete animal; }
At this time, the animal will be deconstructed
This will lead to a virtual deconstruction in the case of no clean release
A normal destructor will not call a subclass destructor. A virtual destructor is needed to solve this problem
Adding a ~ before the analysis of an animal becomes a virtual analysis
The output is
First call the analysis of cat, then call the analysis of animal, then pure virtual = 0
Directly changing to this will result in an error: an external command that cannot be parsed
Points for attention of pure virtual structure analysis:
If we directly change the parent class's Deconstruction to pure virtual, there will be problems that can't be resolved only if the declaration is not implemented
So pure virtual deconstruction needs declaration and Implementation: declaration within class and implementation outside class!!
class Animal{ public: void virtual speak() { cout<<"animal talking"; } virtual ~Animal()=0; }; Animal::~Animal() { }
Output at this time
If there is pure virtual structure, this class is also called abstract class
Upcast downcast
Security insecurity refers to the addressing range of the pointer
The addressing range of converting animal to cat cat is larger than that of animal, and it may be manipulated to content that is not its own
Remember the family tree down conversion
It will be safe to convert the base class into a subclass
This is called up conversion
If polymorphism happens, it must be safe
In the beginning, the addressing range is the large range of subclasses
Game polymorphism instance
First, design the properties and functions of the class
Template
There are many types, and the logic is very similar
//Type parameterization, generic programming template technology
Type substitution will be performed automatically. At the beginning, the parameter is uncertain
We must be able to deduce it. Here is a mistake of two meanings that cannot be deduced
Specify the type when calling
class can also be written as typename, which is equivalent
When using, use explicit type instead of automatic derivation
Sorting example
template <class T> //Tell the compiler that T is a common type void myswap(T &a,T &b){ T temp=a; a=b; b=temp; } template <class T> void mySort(T arr[],int len) { for (int i =0;i<len;i++) { int max=i; for (int j=i+1;j<len;j++) { if (arr[max]<arr[j]) { max=j; } } if (max!=i) { myswap(arr[max],arr[i]); } } } void test6() { char charArr[]="helloworld"; int num=sizeof(charArr)/ sizeof(char);//A general method to find the length of an array mySort(charArr,num); }
char types are sorted by asicii code
The difference between ordinary function and function template
Function templates can also be overloaded
The template is a better match without one more step of implicit type conversion
Internal principle of template mechanism
Custom data types may not be able to process
It will be compiled twice!
Limitation of function template
Solution: need to specify the template
Concretization of formwork
As the following example, common types can be compared using templates
After the user-defined type is put in, an error will be reported. You can know it's a Person class, but you can't compare it
//Solve the above problems by specifying custom data types
class Person{ public: Person(string name,int age) { m_name=name; m_age=age; } string m_name; int m_age; }; template <class T> bool myCompare( T &p1,T &p2) { if (p1==p2) { return true; } return false; } template<> bool myCompare <Person>(Person &p1,Person &p2)//At this time, the type is not T { if (p1.m_age==p2.m_age) { return true; } return false; }
If Person can match both templates, the specific template will be preferred
Use of class templates
Use similar to function template
template <class T1,class T2> class Person2{ public: Person2(T1 age, T2 name) { m_age=age; m_name=name; }; T1 m_age; T2 m_name; };
Difference 1: class template does not support automatic type derivation
Type must be specified explicitly
Difference 2: class templates can have default types
When to create a member function
Member functions are created at run time instead of being created at the beginning
class Person1 { public: void showPerson1() { cout<<"diao Person1"<<endl; } }; class Person3 { public: void showPerson3() { cout<<"diao Person3"<<endl; } }; template <class T> class myclass { public: T obj; void func1() { obj.showPerson1(); } void func2() { obj.showPerson2(); } }; void test8() { myclass <Person1> m; m.func1(); }
m.func2() / / error will be reported
Class template as function parameter
Method 1: specify the incoming type
call
Method 2
Parameter Templating
Do not tell the specific type of function template with class template implementation
Method 3
Global typing templates the entire Person object
View the type of T
Inheritance of class template
The right way to specify the type
More flexible writing method, making subclasses into templates
Passing a T2 to the parent class is used to initialize the allocated memory
In this way, the user can specify the type later
Implement member function outside class template
Methods implemented in class
Out of class implementation
Out of class implementation of common classes
Template class is one more
and
Again, the class template must explicitly specify the type when it is used to generate objects
Class template file code
1. Header file Person.h
// // Created by user1 on 2020/2/24. // Header file declaration #ifndef FENWENJIAN_PERSON_H #define FENWENJIAN_PERSON_H #pragma once using namespace std; #include <iostream> #include <string> template <class T1,class T2> class Person{ public: Person(T1,T2); void showPerson(); T1 mname; T2 mage; }; #endif //FENWENJIAN_PERSON_H
- Person.cpp
#include <iostream> #include "person.h" using namespace std; // // Created by user1 on 2020/2/24. template <class T1,class T2> Person<T1,T2>::Person(T1 name,T2 age) { this->m_name=name; this->mage=age; } template <class T1,class T2> void Person<T1,T2>::showPerson() { cout<<this->mname<<" "<<this->mage<<endl; }
3.main.cpp
#include <iostream> #include "person.h" using namespace std; int main() { std::cout << "Hello, World!" << std::endl; Person <string,int>p1("dasha",12); p1.showPerson(); return 0; }
The above writing method will report two external commands that cannot be resolved
Change "person.h" to "person.cpp"
Reason
Because we couldn't find the code at the time of the link
When main calls the header file, it only sees that the member methods of the header file class template do not generate the code of the source file. The member functions in the source file class template are not created at the beginning, but are created at runtime, so the code cannot be found at the time of linking.
When calling person.cpp, it is equivalent to putting the implementation code into main
Therefore, the template is generally not written in separate files, but in the header file
The header file is changed to. hpp
. hpp is the header file used to represent the template class
summary
Friend function of class template
Friend functions are used to access private properties in a class
Here is the original state
Out of class implementation of friend function -- difficult
According to the following writing method, the declaration compiler of the friend function will be regarded as a normal global function, but it only calls the template class, while its out of class implementation compiler is regarded as a template function, so the sub compiler will first find the implementation of the general global function, but it can't find it!!
resolvent:
1. Use the empty parameter list to tell the compiler that this is the declaration of the template function
But there's still a problem!!
The compiler must be informed of this declaration in advance, not just within the class
There's still a problem with that!
The compiler needs to see the declaration of Person
The application of class template write a general array class
#include <iostream> using namespace std; // // Created by user1 on 2020/2/24. // template <class T> class Myarray { public: Myarray( ) { }; explicit Myarray(int capacity)//Prevent implicit type conversion { this->mcapacity = capacity; this->msize = 0; this->paddress = new T[this->mcapacity]; }; Myarray(const Myarray &array) { this->msize = array.msize; this->mcapacity = array.mcapacity; this->paddress = new T[this->mcapacity]; for (int i = 0; i < msize; i++) { this->paddress[i] = array[i]; } } ~Myarray() { if (this->paddress != NULL) { delete[] this->paddress; this->paddress = NULL; } } //Assignment operator overload Myarray& operator=(Myarray &arr) { //Judge the original data first, and then clear it if(this->paddress!=NULL) { delete [] this->paddress; this->paddress=NULL; } for (int i = 0; i < msize; i++) { this->paddress[i] = array[i]; } return *this; } //[heavy haul] T &operator[](int index) { return this->paddress[index]; } //Tail insertion method void pushback(T val)//Cannot use reference here { this->paddress[this->msize]=val; this->msize++; } //Capacity acquisition int getsize() { return this->msize; } //Get cap int getcap() { return this->mcapacity; } private: T *paddress;//Pointer to heap int mcapacity; int msize; };
C + + type conversion
Minimize type conversion
Static type conversion
It is safe to convert a derived class to a base class, otherwise it is not
Must have parent-child relationships between classes to convert
References can also be converted
Dynamic type conversion
1. The basic type cannot be converted dynamically
Because as long as you lose precision or are not safe, you cannot convert
2. Converting the parent rotor class between the child class and the parent class will result in an error (if there is no polymorphism)
If there is polymorphism (for example, the parent class pointer points to the child class), then the base class can be converted to the derived class and the down conversion can be made
In this way, the normal parent rotor can be created, because the space is created according to the subclass space!
Constant conversion
Used to remove or add const property to a type
Variables that can only be used for references and pointers
Reinterpret transformation (useless)
Very unsafe!!
abnormal
Advantages of C + + exception handling
The basic use of exceptions in C + +
Let's take a look at how early C was handled
Processing of C++
The - 1 thrown is an int type, so catch(int)
If you don't use the exception catcher, it will be brutally terminated
Using exception capture to get the exception, the detection and processing phases are separated
Other types of exceptions can also be thrown
And know that exceptions must be handled to catch
To write a catch double type to connect
How to handle so many types of exceptions:
C + + provides a mechanism to handle many types of exceptions
Custom exception class
myException() is an anonymous object object. No name is needed
Catch custom exceptions and call member functions
summary
Stack unwinding
Abnormal interface declaration
To make exceptions more readable
Throw 3.14 and an error will be reported
Life cycle of abnormal variable
Using references saves cost
Using pointer to control is tedious or good
Abnormal polymorphic use
The reference of the parent class points to the object of the child class
Therefore, you only need to catch a base class to make the code more concise
System standard exception
what method prints the above sentence "age out of range"
Implement an exception class by yourself
Use the system's exception as the base class
It mainly rewrites what method and deconstruction method
string to char * use. c_str()
I / O stream
Standard io:
Input file = = = keyboard
Output file = = = screen
Document io:
String IO:
Standard input
Buffer concept
Read in one character at a time
First took a from the buffer, then s
Got the line break for the third time
cin.get() does not take the newline when reading the string, leaving it in the buffer
getline is to read the newline and throw it away and wait for the next input
No parameter means one character is ignored
It's taken from the buffer and put back
Standard input flow cases
Put the peeped number back into the buffer and then rush it back into num for output
2.
Error case
Entering a char type flag class will destroy it and cause a serious error
Need to use cin.fail()
At this time, the input character type will output abnormal flag bits
Standard output stream
Output format control
To use the header file first
There will be 18 spaces ahead
fill space with*
setf set output format status
Changed decimal to hexadecimal
Uninstall hex install octal
File read / write operation
Output content to a file.
Read data from file
The first way is better