1. Classes and objects

1.1. C++ class definition

Defining a class is essentially defining a data type that contains members and operations.

classThe name of the class {Access modifiers:private/public/protectedData type member variable name; Return value Type Member function name (){}}Copy the code

Sample code:

#include <iostream>
#include <string>
using namespace std;
// Define a User class
class User {
private:	// The following code has private access
    string name;	// Member variable 1
    int age;		// Member variable 2
public:		// Access to the following code is public
    Constructor, which assigns initial values to two members
    User(const string &name, int age) {
        this->name = name;
        this->age = age;
    }
    // Get the value of the member variable
    const string &getName(a) const {
        return name;
    }
    // Get the value of the member variable
    int getAge(a) const {
        returnage; }};int main(a) {
    // Instantiate a User object with a pointer to the heap memory address
    User *user = new User("Xiao Ming".18);
    // Get the values of two member variables of the User object
    cout << user->getName() < <"" << user->getAge() << endl;
    cout << sizeof(User) << endl;
    // Release the heap memory occupied by the User object
    delete user;
    return 0;
}
Copy the code

Const string &getName() const {}

  • The first oneconstIndicates that the return value is a constant.
  • The secondconstIndicates that the function does not and is not allowed to modify a member variable, and is calledConstant function.

1.1.1. Class access modifiers

Class access modifiers are used to encapsulate data and prevent functions from accessing internal members directly.

The modifier role
public Members of the publicIt is accessible outside the class and can read and write values of public member variables directly
protected Protected memberAccessed from a derived class (subclass) with the same effect as public; Is accessed in other classes and has the same effect as private
private Private membersThe values of public member variables cannot be read or written directly from outside the class
Access modifier This class Derived classes Other classes
public ⭕ ️ ⭕ ️ ⭕ ️
protected ⭕ ️ ⭕ ️
private ⭕ ️

1.1.2. Constructors & destructors

A constructor is a special member function of a class that is executed each time a new object of the class is created.

The constructor name is exactly the same as the class name and does not return any type, nor does it return void, and can be used to set initial values for certain member variables.

// The default constructor has no arguments and no function body. Only used to create objects
User() {}// Pass parameters in the constructor to initialize the member
User(const string &name, int age) {
    this->name = name;
    this->age = age;
}
Copy the code

A destructor is a special member function of a class that is executed each time an object created is deleted.

The name of the destructor is exactly the same as the name of the class, prefixed by the tilde ~, and it does not return any values, nor can it take any arguments. Destructors help free resources before exiting the program, such as closing files, freeing memory, and so on.

// Release resources in destructor
~User() {
	delete obj;
}
Copy the code

1.1.3. Static members

Use the static keyword to define a static member that is shared by all class objects.

class Test {
public:
    // Declare a static member of the Test class
    static int i;
};
// Initialize the static member of the Test class
int Test::i = 10;

int main(a) {
    // Outputs a static member of the Test class
    cout << " test1.i: " << Test::i << endl;	/ / [10]
    return 0;
}
Copy the code

1.2. C + + functions

1.2.1. Copy constructor

The copy constructor is a special constructor that initializes a newly created object with a previously created object in the same class. Usually used:

  • Initialize the newly created object by using another object of the same type.
  • The copy object passes it as an argument to the function.
  • Copy the object and return it from the function.
User(const User &user) {
    this->name = user.name;	// copy the value inside and assign it to the member
    this->age = user.age;	// copy the value inside and assign it to the member
}
Copy the code

The compiler generates a copy constructor by default. But if the class has pointer member variables and dynamic memory allocation, it must specify a copy constructor.

1.2.2. Friend functions

A friend function of a class is defined outside the class, but has access to all private and protected members of the class. Friend functions are declared in the class, but they are not member functions.

#include <iostream>
#include <string>
using namespace std;

class User {

private:
    string name;
    int age;
public:
    User(const string &name, int age) {
        this->name = name;
        this->age = age;
    }
    // Declare a friend function
    friend void setAge(User *user, int age);
   	// Declare a friend class
    friend class Admin;
};

// Define friend functions
void setAge(User *user, int age) {
    // Access the private member of the User class directly
    user->age = age;
}

// Define a friend class
class Admin {
public:
    void setName(User *user, const string &name) {
        // Access the private member of the User class directlyuser->name = name; }};int main(a) {
    User *user = new User("Xiao Ming".18);
    cout << user->getName() < <"" << user->getAge() << endl;	// 【 Xiaoming 18】
    
    // Access private members through friend functions
    setAge(user,20);
    // Access private members through friend classes
    Admin *admin = new Admin(a); admin->setName(user, "Xiao gang");
    
    cout << user->getName() < <"" << user->getAge() << endl;	// [Xiaogang 20]
    
    delete user;
    delete admin;
    return 0;
}
Copy the code

1.2.3. Inline functions

If a function is inline, at compile time, the compiler places a copy of the function’s code wherever the function is called.

Inline functions are preceded by the keyword inline and need to be defined before they are called. If the function body is longer than one line, the compiler ignores the inline modifier.

inline int Max(int x, int y) {
    return (x > y) ? x : y;
}

int main(a) {
    cout << "Max (10,20): " << Max(10.20) << endl;	/ / [20]
    return 0;
}
Copy the code

【 Advantages and disadvantages 】

  • Reduce the overhead of function calls.
  • Debugging information is usually more detailed and secure than macro definitions.
  • May increase compilation time, as well as post-compilation volume.


2. Function and operator overloading

2.1. Function overloading

In the same scope, you can declare several functions with the same name but with different arguments of the same form (the number, type, or order of arguments), and you cannot override functions simply by returning different types.

#include <iostream>
using namespace std;
 
class printData {
public:
    void print(int i) {
        cout << "The integer is:" << i << endl;
    }

    void print(double f) {
        cout << "Floating point numbers are:"<< f << endl; }};int main(void) {
   printData pd;
 
   // Output an integer
   pd.print(5);		// [integer: 5]
   // Outputs a floating point number
   pd.print(500.263);	// [float: 500.263]
 
   return 0;
}
Copy the code

2.2. Operator overloading

Overloaded operators are functions with special names consisting of the keyword operator and the operator symbol to be overloaded after it. Like other functions, overloaded operators have a return type and a list of arguments.

// Override the + operator to add two User objects
User operator+ (const User &user) {
    User userResult;
    userResult.name = this->name + user.name;
    userResult.age = this->age + user.age;
    return userResult;
}

int main(a) {
    User *user1 = new User("Xiao Ming".18);
    User *user2 = new User("Xiao gang".20);
    // Add two objects using the overloaded + operator
    User user3 = *user1 + *user2;
    cout << user3.getName() < <"" << user3.getAge() << endl;	// 【 Xiaoming Xiaogang 38】

    return 0;
}
Copy the code

2.2.1. Operators can be overloaded

The operator operation
Binocular arithmetic operator +Plus,-Reduction,*By,/In addition,%modulus
Relational operator = =Equal to,! =Is not equal to,<Less than,>More than,< =Less than or equal to,> =Greater than or equal to
Logical operator `
Unary operator +Is,-Negative,*A pointer,&Take the address
The increment and decrement operator ++Since the increase,--Since the reduction of
An operator `
The assignment operator =+ =- =* =/ =% =& =, `
Space application and release newdeletenew[]delete[]
Other operators (a)Function call,->Member access,.Comma,[]The subscript

2.2.2. Operators cannot be overloaded

The operator The instance
Member access operator .
Member pointer access operator .->
Domain operators : :
Length operator sizeof
Conditional operator ? :
Preprocessing symbol #


3. The RVO and NRVO

RVO (Return Value Optimization) and NRVO (named Return Value Optimization) are compiler optimization techniques. To reduce the return of temporary objects created at the invocation of non-reference objects, as well as the number of copy constructs and destructors.

Let’s start with a phenomenon:

#include <iostream>
#include <string>

using namespace std;

class Test {
public:
    string v;

    Test add(const Test &s) const {
        Test tmp;
        tmp.v = this->v + s.v;
        returntmp; }};int main(a) {

    Test t1;
    t1.v = "Hello";
    Test t2;
    t2.v = "World";

    Test t3 = t1.add(t2);
    cout << t3.v << endl;

    return 0;
}
Copy the code

Running results:

HelloWorld

⭐️

Test tmp; Is a local variable that will be recycled after the function is run, causing the object to which Test t3 points to an exception. But it actually works, for the following reasons:

  • When the function returns, the stack is addedtmpObject through the copy constructorcopyGive me aTemporary objects(we can’t see), and then call the destructor collectiontmpObject.
  • Test t3 = t1.add(t2);, in the=When the number is assigned, theTemporary objects, again by copying the constructorcopytot3, so that the results are preserved correctly.

In summary, the compiler makes two copies of the local variables that should have been destroyed on the stack, making the calculation correct.

However, different compilers have different optimizations for copy times.

  • In VS, one copy (RVO) is performed in DEBUG mode and zero copy (NRVO) is performed in release.
  • In a Clion environment, zero copies (NRVO) are performed.
  • In an Xcode environment, zero copies (NRVO) are performed.

3.1. RVO

RVO optimizations pass in the function’s return value object as an argument at compile time and change the return value to void.

Original function and call method:

// The function takes one argument and returns a value
Test add(const Test &s) const {
    Test tmp;
    tmp.v = this->v + s.v;
    return tmp;
}
// Call mode
Test t3 = t1.add(t2);
Copy the code

RVO optimized pseudo-code (actually more complex, pseudo-code easy to understand) :

// The return value is passed in as an argument, and the function does not need to return the value
void add(Test &result, const Test &t) const {
    Test tmp;
    tmp.v = this->v + t.v;
    result = tmp;
}
// Call mode
Test t3;
t1.add(t3, t2);
Copy the code

After RVO optimization, only one copy (TMP object is copied to result) is required.

3.2. NRVO

NRVO will go one step further and not even create one.

Pseudo-code optimized by NRVO (actually more complex, pseudo-code is easy to understand) :

// The function does not need to return a value
void add(Test &result, const Test &t1, const Test &t2) const {
    result.v = t1.v + t2.v;
}
// Call mode
Test t3;
t1.add(t3, t1, t2);
Copy the code

RVO optimization can be implemented without copying.



4. Packaging

Encapsulation is a concept in object-oriented programming that binds data together with functions that manipulate it, thus ensuring security from interference and misuse.

#include <iostream>
using namespace std;

class Adder {
public:
    // constructor
    Adder(int i = 0) {
        total = i;
    }

    // External interface
    void addNum(int number) {
        total += number;
    }

    // External interface
    int getTotal(a) {
        return total;
    };
private:
    // External hidden data
    int total;
};

int main(a) {
    Adder a;

    a.addNum(10);
    a.addNum(20);
    a.addNum(30);

    cout << "Total " << a.getTotal() << endl;
    return 0;
}
Copy the code


5. Inheritance

Inheritance defines a new class based on a class to improve code reuse and execution efficiency.

Existing classes are called base classes (parent classes), and newly created classes are called derived classes (subclasses).

/ / the base class
class Animal {
    / / eat () function
    / / sleep () function
};


// Derived class (public inheritance)
class Dog : public Animal {
    / / bark () function
};
Copy the code

5.1. Inheritance type

  • Public inheritance: The public members of a base class are also the public members of a derived class. The protected members of a base class are also protected members of a derived class. The private members of a base class cannot be accessed directly by a derived class, but can be accessed by calling the public and protected members of the base class.
  • Protected inheritance: The public and protected members of the base class become protected members of the derived class.
  • Private Inheritance (private) : Public and protected members of the base class become private members of the derived class.

Public inheritance is usually used, with little protected or private inheritance, but if the inheritance type is not specified, the default is private inheritance.

5.2. Multiple inheritance

Multiple inheritance means that a subclass can have more than one parent class, which inherits the characteristics of more than one parent class.

Code structure:

classDerived class name:Derived types1The base class name1, inherited type2The base class name2, {derived class body};Copy the code

More than base class inheritance type can be specified separately, not the same completely consistent.

5.3. Base & Derived Classes

A derived class inherits all of the base class methods except the following:

  • The base class constructor, destructor, and copy constructor.
  • An overloaded operator for the base class.
  • Friend functions of the base class.
#include <iostream>
using namespace std;

/ / the base class
class Shape {
public:
    void setWidth(int w) {
        width = w;
    }

    void setHeight(int h) {
        height = h;
    }

protected:
    int width;
    int height;
};

/ / a derived class
class Rectangle : public Shape {
public:
    int getArea(a) {
        // Use two members of the base class to calculate the area
        return(Shape::width * Shape::height); }};int main(a) {
    // Create a derived object
    Rectangle rect;
    // Call a function of the base class with a derived object
    rect.setWidth(5);
    rect.setHeight(7);

    // Output the area of the object
    cout << "Area:" << rect.getArea() << endl;

    return 0;
}
Copy the code


6. Polymorphism

When a member function is called, different functions are executed depending on the type of object on which the function is called.

6.1. Static polymorphism

Static polymorphism (static linking) is when a function call is prepared before the program executes, that is, it only cares about the type of pointer, not what the pointer points to.

#include <iostream>
using namespace std;

/ / the base class
class Shape {
public:
    void setWidth(int w) {
        width = w;
    }

    void setHeight(int h) {
        height = h;
    }
    // The base class has a calculated area function
    int getArea(a) {
        cout << "Base class function called" << endl;
        return (width * height);
    }

protected:
    int width;
    int height;
};

/ / a derived class
class Rectangle : public Shape {
public:
    // Derived classes also have a computed area function of the same name
    int getArea(a) {
        cout << "Derived class function called" << endl;
        return(Shape::width * Shape::height); }};int main(a) {
    // Polymorphic: Pointers to base classes point to derived objects
    Shape *shape = new Rectangle(a);// Base class pointer calls function
    shape->setWidth(5);
    shape->setHeight(7);

    // Output the area of the object
    cout << shape->getArea() << endl;

    return 0;
}
Copy the code

[Operation results]

The base class function to call

35

At compile time, it has been determined that shape->getArea() calls the getArea() function of the base class, that is, static polymorphism determination

6.2. Dynamic Polymorphism (Virtual Function)

Dynamic polymorphism (dynamic linking) refers to the function call is determined according to the pointer to determine, that is, only care about the pointer to the content, not the type of pointer.

6.2.1. Virtual functions

Is a function declared in the base class using the keyword virtual. When a virtual function in a base class is redefined in a derived class, the compiler is told not to statically link to that function. Use dynamic linking.

// The base class has a compute area virtual function
virtual int getArea(a) {
    cout << "Base class function called" << endl;
    return (width * height);
}
Copy the code

[Operation results]

Derived class function called

35

【 note 】

  • Do not set base class constructors to virtual functions: compilation errorerror: constructor cannot be declared 'virtual'.
  • Base destructors are generally set to virtual functions: to prevent memory leaks in derived classes by only destructing base classes without destructing derived classes.

6.2.2. Pure virtual functions

A meaningful implementation of a virtual function is given in the base class so that the specific implementation of the function can be determined in the derived class. Pure virtual functions are specified by using = 0 in the declaration.

// Base class has a pure virtual function that computes area
virtual int getArea(a) = 0;
Copy the code

6.2.3. An abstract class

An abstract class is one in which at least one function is declared pure virtual.

  • An abstract class cannot be used to instantiate an object; it can only be used as an interface. Attempting to instantiate an object of an abstract class results in a compilation error.
  • Derived classes must override the pure virtual functions of the base class, or this will result in a compilation error.