C + + details

Keywords: calculator C Programming

Article directory

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
  1. 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


Published 55 original articles, won praise 31, visited 2328
Private letter follow

Posted by Jabop on Mon, 24 Feb 2020 23:27:01 -0800