One: The copy constructor is called only at initialization

The copy constructor is called only at initialization. Assignment after initialization does not call the copy constructor, but simply copies the member variable.

Type conversion constructors

You can see, executec1 = 99 automatically casts the constructor to generate a temporary Complex object.

In fact, we can see that the constructor in the previous example can be used as either an implicit type conversion or an explicit initialization, so that the compiler knows exactly which one it isexplicitExplicit: explicit cannot be used for type conversions.

Destructors

When the life of a variable ends, the destructor is called.

The object from new is not destructed automatically, only when it is deleted.

Static member variables and functions

The initialization of a static member variable must be declared outside the class and can be initialized or uninitialized.

class Complex {
public:
    static int cc;
    double real,imag;
};

int Complex::cc = 1;
Copy the code

Member objects and enclosing classes

  • If you have a member object, you have to write a constructor, otherwise what constructor is used to initialize that member object
  • Member objects are initialized with an initializer list.

Constant object, constant member function

  • Constant objects can only use constructors, destructors, and const constant functions.

  • A const function cannot modify a member variable.

  • In particular, functions that are const are overloaded.

Friend functions and friend classes

  • A friend function of a class can access private members of that class

  • The private member price of Car can be accessed in ModifyCar because the friends are specified
  • The MostExpensiveCar function is… , should also specify friends

This code specifies that the CDriver class is a friend of the CCar class

friend class CDriver; // Declare CDriver as a friend
Copy the code

Operator overloading

1. Basics of overloading

2. Overloading the assignment operator

  • As you can see, the String default constructor executesstr(new char[1])andstr[0]=0To form an empty string
  • Overloading the assignment operator, when the assigned value is char *, then firstdelete []strAnd then new one, and then strcpy to get it
  • Note that the return value of this assignment function isString &I tried something else as a return value and nothing worked, so keep that in mind for now.

  • String s2 = "hello"This is the initialization statement that calls the constructor.

This is a shallow copy, because we’re not overloading String to String assignments, so this is a shallow copy, copying the STR pointer. This can lead to catastrophe, as follows:

When either S1 or S2 is assigned to a char*, the same STR will be deleted, or when either of the destructors will be deleted. So add the following code:

But there are still problems with this, see below:

If s=s, delete the only STR. So the correct way is to add a check, if equal, then directly return!


Oh! So the reason why we return String& is because we always do it with =, right

  • Void does not work, because it cannot wait
  • String doesn’t work because it’s executing(a=b)=cIn this case, we actually want a to be equal to c, and we need the result of a=b to be a reference to A in order to get a=c

The final problem is that if you don’t write the copy constructor, the compiler defaults to a shallow copy.

String( String & s) {
    str= new char[strlen(s.str)+1];
    strcpy(str,s.str);
}
Copy the code

3. Operator overload as friend function

Normally, we would override the operator as a member function of class, not as a global function, but sometimes it would have to be a global function, such as in the 5+ C case, where we would never be able to override int. For global functions, if you want to access private variables, you have to make friends.

4. Overloading of stream (insert/extract) operators

  • Make a global function that says << overload as above, take an ostream & and CStudent argument, and call ito << s.nAgeOutput, and return a reference to ostream

Ok, before writing, you need to know:

  • Cin is of type istream
  • Cout is of type ostream

  • Cout is very simple

  • Cin is a little more complicated, so I won’t go into it.

5. Overloading of the type conversion operator & the increment and decrement operator

  • A type conversion operator is the name of a class, such as double, that converts data to double

    operator double(a) { // Type conversion overloading does not require the return type keyword double
        return real;
    }
Copy the code
  • This is an overload of the double conversion, returning real. As you can see, this overload is written a little bit differently. We don’t write the return type, because it must be double!
  • Double n = 2 + c; double n = 2 + c; double n = 2 + c

6. Overloading of the increment and decrement operators

  • ++ I: as unary
  • I++ : as binary, write one more useless parameter

#include <iostream>
using namespace std;

class CDemo {
private:
    int n;
public:
    CDemo(int n_=0) : n(n_) {

    }

    CDemo & operator+ + ();// Preload ++
    CDemo operator+ + (int); // reload ++
    CDemo & operator--(); // reload preloaded --
    CDemo operator--(int); // reload after --

    operator int(a) { // (int) type cast
        returnn; }}; CDemo & CDemo::operator+ + () {// Preload ++
    ++n;
    return *this;
}

CDemo CDemo::operator+ + (int) { // reload ++
    CDemo tmp(*this);
    n++;
    return tmp;
}

CDemo & CDemo::operator--() { // reload preloaded --
    --n;
    return *this;
}

CDemo CDemo::operator--(int) { // reload after --
    CDemo tmp(*this);
    n--;
    return tmp;
}


int main(a)
{
    CDemo d(5);
    cout << (d++ ) << ","; // equivalent to d.perator ++(0);
    cout << d << ",";
    cout << (++d) << ","; // equivalent to d.perator ++();
    cout << d << endl;

    cout << (d-- ) << ","; // equivalent to d. opperator --(0);
    cout << d << ",";
    cout << (--d) << ","; // equivalent to d.opperator --();
    cout << d << endl;

    return 0;
}
Copy the code

Output:

5,6,7,7
7,6,5,5
Copy the code

Note:

  • wecout << d++Instead of overloading <<, we cast an int to make an int.
  • Note that,++dOur return value is zeroCDemo &Lambda is a reference, because we often have ++ I = 1.d++The return value ofCDemoI++ is a value, because we can’t i++ = 1. I++ returns a temporary value, and the actual value has changed, so it’s clear from this code:
CDemo & CDemo::operator+ + () {// Preload ++
   ++n;
   return *this;
}
CDemo CDemo::operator+ + (int) { // reload ++
   CDemo tmp(*this);
   n++;
   return tmp;
}
Copy the code

Eight, inheritance,

1. Concepts of inheritance and derivation

  • Inheritance: When defining A new class B, if the class is similar to an existing class A (meaning that B has all the characteristics of A), then A can be A base class and B A derived class (also called A subclass) of the base class.

    • Derived classes are created by modifying and extending the base class.
    • In derived classes, you can extend new member variables and member functions.
    • Once defined, a derived class can be used independently of the base class.
  • A derived class has all the member functions and variables of the base class, whether private, protected, or public

    • The private members of the base class cannot be accessed in the member functions of the derived class
  • Class Derived class name: public base class name {};

  • cover

    • A derived class may define a member with the same name as a member of the base class. This is called an override
    • When accessing such a member in a derived class, the default is to access a member defined in the derived class
    • To access a member of the same name defined by the base class in a derived class, use the scope symbol:
    • In general, base and derived classes do not define member variables with the same name, but it is common to have member functions with the same name
  • The memory space of a derived object

    • The volume of the derived object is equal to the volume of the base object, plus the volume of the derived object’s own member variables.
    • A derived object contains a base object, and the base object is stored before the new member variable of the derived object

Inheritance example procedures: Student Status management:

#include <iostream>
using namespace std;


class CStudent { / / the base class
private:
    string name;    / / name
    string id;  // id
    char gender;    / / gender
    int age;    / / age
public:

    void SetInfo(const string name_, const string id_, int age_, char gender_);
    string GetName(a);
    void PrintInfo(a);
};

void CStudent::SetInfo(const string name_, const string id_, int age_, char gender_) {
    name = name_;
    id = id_;
    gender = gender_;
    age = age_;
}

string CStudent::GetName(a) {
    return name;
}

void CStudent::PrintInfo(a) {
    cout << "Name: " << name << endl;
    cout << "ID: " << id << endl;
    cout << "Gender: " << gender << endl;
    cout << "Age: " << age << endl;
}

class CUndergraduateStudent : public CStudent { // Derived from CStudent class
private:
    string department;
public:
    void SetInfo(const string name_, const string id_, int age_, char gender_, string department_); // Override the base class method
    void QualifiedForBaoyan(a); // Override the base class method
    void PrintInfo(a); // Override the base class method
};

void CUndergraduateStudent::QualifiedForBaoyan(a) {
    cout << "qualified for baoyan" << endl;
}

void CUndergraduateStudent::SetInfo(const string name_, const string id_, int age_, char gender_, string department_) {
    CStudent::SetInfo(name_, id_, age_, gender_); // Call the base class method
    department= department_;
}

void CUndergraduateStudent::PrintInfo(a) {
    CStudent::PrintInfo(a);// Call the base class method
    cout << "Department: " << department << endl;
}

int  main(a)
{
    CUndergraduateStudent s2;

    s2.SetInfo("Harry Potter "."118829212".19.'M'."Computer Science");
    cout << s2.GetName() < <"" ;
    s2.QualifiedForBaoyan(a); s2.PrintInfo(a);return 0;
}
Copy the code

Output:

Harry Potter  qualified for baoyan
Name: Harry Potter 
ID: 118829212
Gender: M
Age: 19
Department: Computer Science
Copy the code

2. Inheritance and composition

  • This is the core difference between inheritance and composition.

  • Let’s look at compound relationships:

3. Derived classes override base class members

4. Protected members of the class

  • Protected members are given one more privilege than private members. Member functions of derived classes can access protected members of the base class. So, if you want a function of a derived class to use some of the variables or functions of the base class, use protected.

  • Note that protected is only accessible in the member functions of derived classes.

5. Constructors of derived classes

The specification uses an initializer list to initialize the base object contained in a derived class, as shown in the following example.

The reason for the error constructor is that legs and color of the base class are private and the parent class cannot access them.

  • When creating an object of derived class:

    • The constructor of the base class is first executed to initialize the members of the derived object from the base class.
    • The constructor of the member object class is then executed to initialize the member object in the derived object.
    • Finally, the derived class’s own constructor is executed
  • When a derived object dies:

    • The derived class’s own destructor is executed first
    • The destructor of each member object class is executed in turn
    • Finally, the destructor of the base class is executed
  • Destructors are called in the opposite order to constructors

6. Compatibility rules of assignment for public inheritance

  • Objects of derived classes can be assigned to objects of base class

    • b = d;
  • Derived class objects can initialize base class references

    • base & br = d;
  • The address of a derived object can be assigned to a base pointer

    • base * pb = & d

7. Direct and indirect base classes

  • When an object of a derived class is generated, all the base class constructors are executed layer by layer, starting with the topmost base class, and finally executing its own constructors
  • When an object of a derived class dies, its own destructor is executed first, and then the destructors of each base class are executed bottom-up

Look at an example:

#include <iostream>
using namespace std;

class Base { / / the base class
protected:
    int n;
public:
    Base(int n_=0) : n(n_) {
        cout << "Base constructed" << endl;
    }
    ~Base(){
        cout << "Base destructed"<< endl; }};class Derived : public Base {
public:
    Derived(int n_) :Base(n_) {
        cout << "Derived constructed" << endl;
    }
    ~Derived(){
        cout << "Derived destructed"<< endl; }};class MoreDerived : public Derived { // Directly Base class Derived, do not declare indirect Base class Base
public:
    MoreDerived() : Derived(0) {
        cout << "MoreDerived constructed" << endl;
        this->n = 0;
    }
    ~MoreDerived() {
        cout << "MoreDerived destructed"<< endl; }};int  main(a)
{
    MoreDerived m;

    return 0;
}
Copy the code

Output:

Base constructed       
Derived constructed    
MoreDerived constructed
MoreDerived destructed 
Derived destructed     
Base destructed 
Copy the code

Nine, polymorphism

1. Basic concepts of virtual functions and polymorphism

  • In a class definition, a member function preceded by the virtual keyword is a virtual function
  • The virtual keyword is used only in function declarations in class definitions, not in function bodies
  • Static member functions cannot be virtual

  • Pointers to derived classes can be assigned to Pointers to base classes

  • When a base pointer is used to call a virtual function of the same name in a base and derived class:

    • If the pointer points to an object of the base class, it is called a virtual function of the base class
    • If the pointer points to an object of a derived class, the derived class’s virtual function is called

    This mechanism is called polymorphism.

  • An object of a derived class can be assigned a reference to the base class

  • When a base class reference calls a virtual function of the same name in a base and derived class:

    • If the reference refers to an object of the base class, then it is a virtual function of the base class
    • If the reference refers to an object of a derived class, then the virtual function of the derived class is called

This mechanism is also called polymorphism.

Look at an example:

#include <iostream>
using namespace std;

class Base {
public:
    virtual void someVirtualFunction(a) {
        cout << "Base someVirtualFunction()"<< endl; }};class Derived : public Base {
public:
    virtual void someVirtualFunction(a) {
        cout << "Derived someVirtualFunction()"<< endl; }};int  main(a)
{
    Derived d;
    Base *pb, b;

    / / pointer
    pb = &d;
    pb->someVirtualFunction(a);// Output "Derived someVirtualFunction()"

    pb = &b;
    pb->someVirtualFunction(a);// Output "Base someVirtualFunction()"

    / / reference
    Base &br1 = d;
    br1.someVirtualFunction(a);// Output "Derived someVirtualFunction()"

    Base &br2 = b;
    br2.someVirtualFunction(a);// Output "Base someVirtualFunction()"

    return 0;
}
Copy the code

2. Polymorphic example: Heroes of Might and Magic

  • There are many kinds of monsters in the game. Each monster has a class corresponding to it, and each monster is an object, such as Dragon, Wolf, Ghost and so on
  • Every monster has vitality and attack
  • Monsters can attack each other, and there are corresponding actions when attacking enemies and being attacked, which are realized through the member functions of the object
  • When the game version is upgraded, a new monster will be added – thunderbird. How can you program the upgrade so that the code changes and additions are small?

Let’s first look at non-polymorphic implementations:

  • It is very troublesome to have N Attack and FightBack functions, and when a new monster is added, it is necessary to increase the Attack and FightBack of all monster classes, and the program changes greatly

Let’s look at the implementation of polymorphism:

  • Write Attack, Hurted and FightBack for each monster class.

#include <iostream>
using namespace std;

class Creature {
protected:
    int nLifeValue, nPower;
public:
    virtual void Attack(Creature *p) {}
    virtual void Hurted(int power) {}
    virtual void FightBack(Creature *p) {}};class Dragon : public Creature {
public:
    virtual void Attack(Creature *p) {
        p->Hurted(nPower);
        p->FightBack(this);
    }

    virtual void FightBack(Creature *p) {
        p->Hurted(nPower/2);
    }

    virtual void Hurted(int power) { nLifeValue -= power; }};class Wolf : public Creature {
public:
    virtual void Attack(Creature *p) {
        p->Hurted(nPower);
        p->FightBack(this);
    }

    virtual void FightBack(Creature *p) {
        p->Hurted(nPower/2);
    }

    virtual void Hurted(int power) { nLifeValue -= power; }};class Ghost : public Creature {
public:
    virtual void Attack(Creature *p) {
        p->Hurted(nPower);
        p->FightBack(this);
    }

    virtual void FightBack(Creature *p) {
        p->Hurted(nPower/2);
    }

    virtual void Hurted(int power) { nLifeValue -= power; }};int  main(a)
{
    Dragon dragon;
    Wolf wolf;
    Ghost ghost;

    dragon.Attack(&wolf);
    dragon.Attack(&ghost);

    return 0;
}
Copy the code

3. Polymorphic example: geometric shape program

Sample Input: 
3
R 3 5 
C 9 
T 3 4 5

Sample Output
Triangle: 6
Rectangle:15
Circle:254.34
Copy the code

  • CShapeIt’s all base classes, hisAreaandPrintInfoIs a pure virtual function that has no body, because a CShape object has no area or Info.
  • The derived rectangle class isCRectangle, with an extra W,h for width and height… And roundCCircleAnd so on.

I wrote the derived class hereAreaandPrintInfo

CShape *pShapes[100];
intMyCompare(constvoid *s1, constvoid *s2);
intmain()
{
    inti;
    intn;
    CRectangle *pr;
    CCircle *pc;
    CTriangle *pt;
    cin >> n;   // Number of outputs
    for (i = 0; i < n; i++)
    {
        char c;
        cin >> c;
        switch (c)
        {
        case 'R':
            pr = new CRectangle(a); cin >> pr->w >> pr->h; pShapes[i] = pr;break;
        case 'C':
            pc = new CCircle(a); cin >> pc->r; pShapes[i] = pc;break;
        case 'T':
            pt = new CTriangle(a); cin >> pt->a >> pt->b >> pt->c; pShapes[i] = pt;break; }}qsort(pShapes, n, sizeof(CShape *), MyCompare);
    for (i = 0; i < n; i++)
        pShapes[i]->PrintInfo(a);return 0;
}

int MyCompare(const void *s1, const void *s2)
{
    double a1, a2;
    CShape **p1; // s1,s2 is void *, can not write "* s1" to obtain the contents of s1
    CShape **p2;
    p1 = (CShape **)s1; //s1,s2 points to an element in a pShapes array of type CShape*
    p2 = (CShape **)s2; // p1 and p2 are Pointers to Pointers of type CShape**
    a1 = (*p1)->Area(a);// * p1 is of type Cshape*, so this clause is polymorphic
    a2 = (*p2)->Area(a);if (a1 < a2)
        return - 1;
    else if (a2 < a1)
        return 1;
    elsereturn 0;
}
Copy the code

4. Calling a virtual function from a member function that is not constructed/destructed is polymorphic

Example:

#include <iostream>
using namespace std;

class Base {
public:
    void fun1(a) {
        fun2(a);Calling a virtual function in a member function that is not a constructor or destructor is polymorphic
    }

    virtual void fun2(a) {
        cout << "Base fun2()"<< endl; }};class Derived:public Base {
public:
    void fun2(a) { // Virtual functions of derived classes may not have the keyword virtual
        cout << "Derived fun2()"<< endl; }};int  main(a)
{
    Derived d;
    Base *pb = &d;

    pb->fun1(a);return 0;
}
Copy the code

Func1 is a normal function. It called the virtual function func2. Func1 in main will execute func2 polymorphically, so it says:

Derived fun2(a)
Copy the code

Call virtual functions in constructors and destructors, not polymorphisms

  • You can determine at compile time whether the function you are calling is defined in your own class or base class. You do not wait until run time to decide whether to call your own or a derived function

The following cases:

#include <iostream>
using namespace std;

class Base {
public:
    virtual void Hello(a) {
        cout << "Base Hello()" << endl;
    }
    virtual void Bye(a) {
        cout << "Base Bye()"<< endl; }};class Derived:public Base {
public:
    void Hello(a) {
        cout << "Derived Hello()" << endl;
    }

    void Bye(a) {
        cout << "Derived Bye()" << endl;
    }

    Derived() {
        Hello(a); } ~Derived() {
        Bye();
     }
};

class MoreDerived:public Derived {
public:
    void Hello(a) {
        cout << "MoreDerived Hello()" << endl;
    }
    void Bye(a) {
        cout << "MoreDerived Bye()" << endl;
    }
    MoreDerived() {
        Hello(a); } ~MoreDerived() {
        Bye();
    }
};

int  main(a)
{
    MoreDerived md; // Output :Derived Hello(), MoreDerived Hello()
    cout << endl;

    Base *pb = &md; 
    pb->Hello(a);// Polymorphic output :MoreDerived Hello()

    cout << endl;

    return 0;
    // Destructor output :MoreDerived Bye(), Derived Bye()
}
Copy the code

5. The access permission of the virtual function depends on the access permission of the base class virtual function

6. Virtual functions only need base class +virtual, subclass can be added or not added

7. Realization principle of polymorphism

  • The key to “polymorphism” is that when a virtual function is called through a base class pointer or reference, it is not determined at compile time whether the function is called from the base class or from a derived class until it is determined at run time —- this is called “dynamic binding”

  • The key of polymorphic realization — virtual function table

    • Every class that has virtual functions (or a derived class from a class that has virtual functions) has a virtual table, and Pointers to the virtual table are placed in any object of that class
    • The virtual function table lists the virtual function addresses of this class
    • The extra four bytes are used to place the address of the vtable at the beginning of the object.
    • Polymorphic function call statements are compiled into a series of instructions to look up the address of the virtual function in the virtual function table based on the address of the object pointed to (or referenced by) the base class reference

To put it simply, polymorphic calling functions do not simply call an address, but rather go to the virtual function table to find that address

The address of pa’s virtual function table is changed, so that when Func is called, a’s Func is called

Virtual destructors

Virtual destructors are recommended!

Question:

  • If a virtual destructor is not given to the base class, then the base destructor is usually only called when a pointer to the base class is used to delete a derived object.

Solutions:

  • Declare the destructor of the base class virtual

  • When a derived object is deleted through a pointer to a base class, only the destructor of the base class is normally called

    • However, when deleting an object of a derived class, the destructor of the derived class should be called first, and then the destructor of the base class.
  • Solution: Declare the destructor of the base class virtual

    • Destructors for derived classes may be virtual undeclared
    • When a derived object is deleted through a pointer to a base class, the destructor of the derived class is called first, and then the destructor of the base class
  • In general, if a class defines a virtual function, the destructor should also be virtual. Alternatively, if a class is intended to be used as a base class, the destructor should also be defined as virtual.

  • Note: Virtual functions are not allowed as constructors

Pure virtual functions and abstract classes

class A {
private: 
  int a;
public:
  virtual void Print( ) = 0 ; // A pure virtual function
};
Copy the code

  • Classes that contain pure virtual functions are called abstract classes

    • Abstract classes can only be used as base classes to derive new classes. Objects of abstract classes cannot be created
    • Pointers and references to abstract classes can point to objects of classes derived from abstract classes

  • The reason why a member function of an abstract class can call a pure virtual function is because the member function of the base class calls the virtual function in a polymorphic form.
  • The constructor/destructor cannot call a pure virtual function because it is not polymorphic, so it cannot call a function that does not have a function body.
  • It inherits from an abstract class and must implement all pure virtual functions to not be an abstract class, much like Java.

Input, output and file operation

1. Classes related to input and output streams

  • Ios is an abstract base class, derived from istream and ostream
  • Istream is the stream class for input, and CIN is the object of that class
  • Ostream is the stream class for output, and cout is the object of that class
  • Ifstream is a class for reading data from a file
  • Ofstream is a class that writes data to a file
  • An iostream is a class that can be used for both input and output
  • Fstream is a class that can both read from and write to a file

  • Cin corresponds to the standard input stream, used to read data from the keyboard, and can also be redirected to read data from a file
  • Cout corresponds to the standard output stream, which is used to output data to the screen, and can also be redirected to write data to a file
  • Cerr corresponds to the standard error output stream and is used to output error messages to the screen
  • Clog corresponds to the standard error output stream and is used to output error messages to the screen
  • The difference between CERR and CLOG is that CERR does not use buffers and directly outputs information to the display. The output to cloG is stored in the buffer until the buffer is full or flushed

If the input is from a file, the end is finished. If it is keyboard input, receiveCtrl+ZIs over.

Another difficulty is that although the operator>> overload returns an istream & and should not be used as a condition for a while, istream overloads the cast operator to bool.

A code example is as follows:

#include "bits/stdc++.h"
using namespace std;
int main(a){
    int x;
    while (cin >> x){
        cout << "echo : " << x << endl;
    }
    system("pause");
}
Copy the code

The output is as follows:

PS D:\leetcode> g++ a.cpp ; ./a
1 2 3 4
echo : 1
echo : 2
echo : 3
echo : 4^D Press any key to continue.Copy the code

istream& getline(char * buf, int bufSize)
Copy the code

The getline is delimited by \n

istream& getline(char * buf, int bufSize,char delim);
Copy the code

This getLine is delimited by delim, not by \n

  • The nice thing about getLine is that the bufSize includes the ending \0, so the bufSize is as big as the char array is. If it reaches or exceeds
  • Getline returns 0 when it reaches the end of a read or exceeds bufSize.

cin.eof(a);// Determine whether the input stream is finished
cin.peek(a);// Reads the next character of the input stream, but does not remove it from the stream (glimpse)
cin.pushback(a);// Put the character into the input stream
cin.ignore(int nCount=1.int delim=EOF);// Delete at most nCount characters from the input stream, or terminate when EOF is encountered
Copy the code


Use Freopen for input/output redirection.

  • In this case, the standard output goes to test.txt, and the standard error output goes to the terminal

  • Standard input is redirected to a file.

Xi. Template

1. Function templates