C++ Review Notes

Recently I started preparing for the Spring Festival Entrance. Writing a blog should be a review

1. Get the number of elements in the array

int arr[] = {1,2,3,4,5,6,7,8,9};
cout<<"The array has:"<<sizeof(arr)/sizeof(arr[0])<<endl;
cout<<"The first address of the array:"<<arr<<endl;
cout<<"The first address of the array element:"<<&arr[0]<<endl;

2. Inverse Array Order

int arr[] = {1,2,3,6,5,8};
int len = sizeof(arr)/sizeof(arr[0]),temp;//Gets the length of the array
// cout<<len;
int arr2[len];
for(int i = len-1;i>=0;i--) {
    // cout<<len-i-1<<" ";
for(int i = 0;i<len;i++){

3. Pointer and Reference

//On x86 operating systems, pointers account for 4 bytes and on 64-bit operating systems for 8 bytes
    int a = 10;
    int *p = &a;  //The pointer must be initialized (pointed) or it will become a wild pointer
    *p = 1000;  //The address where p points to a, *p stands for the content of the address, and modifying *p is equivalent to modifying a
    cout<<"At this time a The value was modified to:"<<a<<endl;
    cout<<"sizeof(int *)"<<sizeof(p)<<endl;
//Pointer Constant and Constant Pointer
int a = 10;
int b = 20;
// constant pointer,Can only modify content, point to non-modifiable
int * const p = &a;
*p = 100;
// Constant pointer, can only modify pointer, cannot modify content
const int * p2 = &a;
p2 = &b;
// Mixed mode, can not be modified
const int * const p3 = &a;

Memory: the pointer constant const modifies the address of p to a, while const points to unmodifiable

Constant pointer const modifies *p, *p is content, content cannot be modified

//Pointer and Array
    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int *p = arr;
    cout<<"The first element of the array:"<<*p<<endl;
    p++;  //One way to write it is P+4, because int s take up four bytes, but there is a potential danger that different processors may have different data types
    cout<<"The second element of the array:"<<*p<<endl;

Pointers also have a way to solve the problem of modifying parameters and a way to use references

void swap01(int *p1 , int *p2) {     int temp = *p1;     *p1 = *p2;     *p2 = temp; } 
  //Pointer Style
   int a = 10; int b = 20; swap(&a,&b); cout<<a<<endl; cout<<b<<endl;
  //By reference
    int a = 10,b=20;     swap01(a,b);//Passing by reference is similar to passing by pointer     cout<<a<<endl;     cout<<b<<endl;

But note that:

1. References must be initialized, 2. Once a reference is initialized, it cannot be changed (because the essence of a reference is a constant pointer, that is, -->type* const p)
References can also be used - > function references as return values
int& test01(){//Used to return static variable references     static int a = 6;     return a; }
  int& ref = test01(); cout<<"ref:"<<ref<<endl;  //Output 6 test01() = 666;//Use reference as return value, then function can be left modified cout<<"ref:"<<ref<<endl;  //Output 666

Right Value Reference: A right value reference has an important property - it can only be bound to an object that will be destroyed. Therefore, we are free to "move" a resource referenced by one right value into another object.

4. Function overload

Three conditions need to be met:

1. Must be in the same scope 2. Function names are the same 3. Parameter types, number, or order are different
void fun(int &a){
//Variable is called
void fun(const int &a){
//Constant is called
void func(int a){


5. Access rights to classes

1.public   Accessible both inside and outside classes
2.protected  Within a class, outside a class, children can't access the contents of the parent
3.private    Within class may not, outside class may not    You cannot access content in the parent
struct Default is public  class Default is private

The main difference between protected and private is evident in inheritance:

When using protected inheritance, derived classes have access to members within the class, while when using private inheritance, derived classes do not have access to members within the class


6. Various constructors for classes and classes

Class members are called first from branch to whole, and destroyed first from branch to branch
For example, if I wrote a Person class and a Phone class and used phone to create a phone in person, the call would look like this
class Phone{
    Phone(string name) :m_PName(name) {
    string m_PName;
        cout<<"Phone Destruction of"<<endl;

class Person{
        cout<<"Person Destruction of"<<endl;
    string m_name;
    Phone m_phone;


C++ compiler default and auto-complete, 1. Default Construct 2. Default destructor 3. Default Copy
Invocation rules: 1. If the parametric construct is overridden, the compiler no longer provides the default construct 2. If the copy construct is overridden, neither default nor parameter provides the default
Usually we override the constructor to initialize, the destructor to release the heap area data, and the copy construct to achieve deep copy (right in the figure below)


Hazard of shallow copies: When a destructor executes (the newly opened pointer points to the same space as the pointer), the heap data is released twice, causing the program to run



1. Global static variables

Static before global variables becomes static data (even static local variables inside functions) and is stored in the global data area. Data in the global data area does not free up space because the function exits. *

Scope: From the beginning of definition to the end of the file. Initialization: Without initialization, automatic initialization is 0

As follows, we did not assign a value to num display, but the result was 0

using namespace std;
static int num;//Global static variable
int main(){
    cout<<"num: "<<num<<endl;
    return 0;


2. Local static variable

Same as above in Global Data Area

Scope: Local scope, but not destroyed after leaving scope, resident in memory. Initialization: Without initialization, automatic initialization is 0

As follows, a local static variable is declared in the func and is not initialized, but 0 is called once (automatic initialization) and 1 is called twice, which means the data is worth preserving (i.e., in the global data area)

using namespace std;

void func(){
    static int num;//Declare a local static variable

int main(){
    return 0;


3. Static Functions

A function is defined as a static function by adding static before its return type

Functions are extern ally by default, but are not visible in other files after adding a static, such as the func in the code above with a static modification, which is not perceived in other files

4. Static members of classes

A static member class is a shared member among all objects of a class, not a member of an object.

For multiple objects, static data members store only one copy for all objects to share

In the following program, we assign a and only output the result of the last assignment because a is stored in only one copy. Non-static members are maintained by each object individually.

using namespace std;

class Static_exp{
    static int m_a;
    int m_b;
    Static_exp(int a,int b){
        this->m_a = a;
        this->m_b = b;
    void get_a_b(){
        cout<<this->m_a<<" "<<this->m_b<<endl;

int Static_exp::m_a=0;//Be careful to initialize
int main(){
    Static_exp s1(10,10),s2(20,20),s3(30,30);
    return 0;

5. Class static functions

Static member functions, like static member variables, are static members of classes, not object members

Therefore, reference to static members does not require an object name

And 1. All objects share the same function 2. Static member functions can only access static member variables

class Person{
            //Static member function
            static void func(){
                m_A = 100; //Static member functions can access static member variables
                // m_B = 200; //Error!! Cannot access non-static member variables
        static int m_A;//Static member variable
        int m_B;//Non-static member variable

Normal member functions generally imply a this pointer, which points to the object of a class itself, because a normal member function is always specific to the specific object of a class. This is usually the default. For example, the function fn() is actually this->fn(). However, compared to normal functions, static member functions do not have this pointer because they are not associated with any objects. In this sense, it cannot access non-static data members belonging to class objects or non-static member functions, it can only call the remaining static member functions.

8.C++ Memory Partition Model

C++ memory models can be divided into:

1. Code area: Binary code, managed by OS

2. Global area: further subdivided into static and constant storage

Static storage: mainly stores global static variables, local static variables, global variables, and virtual function tables

Constant Storage: Global Constants, Function Pointer, Constant Array

3. Stack area: Automatically allocated and released by the compiler, storing function parameter values, local variables, etc.

4. Heap area: Manually allocated and released by the programmer, not released by the programmer by the OS after the program has finished running



Do a few simple validations

class MyClass {
    int m_c;
    static int m_d;

int MyClass::m_d = 0;

const int c_g_a = 10;
int main() {
    int a = 10;
    int b = 10;
    static int c = 10;
    const int c_l_a = 20;

    cout << "Local variable address:" << (int)&a << endl;
    cout << "Local variable address:" << (int)&b << endl;

    cout << "Global variable address:" << (int)&m_a << endl;
    cout << "Global variable address:" << (int)&m_b << endl;

    MyClass mc;
    cout << "MyClass Variable address:" << (int)&mc << endl;
    cout << "MyClass In m_c: " << (int)&mc.m_c << endl;

    cout << "MyClass In m_d(Static Member Properties): " << (int)&mc.m_d << endl;
    cout << "Local static variable c: " << (int)&c << endl;

    cout << "const Modified global variables a: " << (int)&c_g_a << endl;
    cout << "const Modified local variables a: " << (int)&c_l_a << endl;

    return 0;


There is a significant difference between the addresses of the red area (global area) and the yellow area (stack area). Note that the addresses of the two adjacent global areas are exactly 4 bytes apart, which corresponds to the int variable

Stack data and stack data are released at different times, and the lifecycle of the stack is determined by the programmer. Stack data is released when the variable is used, as follows

using namespace std;
int* func() {
    int a=10;//Local variables are stored in the stack area and the stack area data is automatically released after execution
    return &a;
int main() {
    int *p = func();
    cout << *p << endl;
    cout << *p << endl;

    return 0;

The first time normal output is reserved by the compiler, but it is reserved once, and the second time it is scrambled.



Comparing with the data from the above heap area, we can open a in func() and print it in the heap area without any problems.

using namespace std;
int* func() {
    int *a= new int (666);
    return a;
int main() {
    int *p = func();
    cout << *p << endl;
    cout << *p << endl;
    cout << *p << endl;

    return 0;


Questions about virtual function tables can be found in this blog: C++ Virtual Function Table Analysis | Leo's Blog (leehao.me)

A virtual table is an array of pointers whose elements are pointers to virtual functions, and each element corresponds to a function pointer to a virtual function.

9.this pointer

Role: 1. Resolve name conflicts, 2. Return the object itself with *this: The essence of this pointer is pointer constant, that is, pointing to unmodifiable

using namespace std;
class Person_this {
    Person_this(int age) {
        this->age = age;//Without this, it would be a naming conflict
    }//1.When the parameter has the same name as the member variable, use the this Pointer to differentiate

    Person_this& PersonAddAge(Person_this &p) {
        this->age += p.age;
        // this point p2 The pointer, and*this What I'm pointing at is p2 Ontology
        //Return the object itself
        return *this;
    //Constant function
    void show_person() const {
        //Add const Modified by this The pointer would have been: Perosn* const this  Become const Perosn* const this
        //this->age = 100;//Report errors
      this->m_B = 200;//Correct
} int age; mutable int m_B;//Add mutable After a keyword, it becomes a special variable that can be modified even in a constant function }; void test06() { const Person_this p;//Declared at this time p As a constant object, a constant object cannot modify its properties--->mutable Except modified // And a constant object can only call a constant object //p.age = 10;//Error immediately, const Object can only be modified mutable Modified p.m_B = 100; p.show_person(); cout << "m_B:" << p.m_B << endl; Person_this p1(10); Person_this p2(10); cout << "age:" << p1.age << endl; // Chain programming idea p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1); cout << "p2:age:" << p2.age << endl; } int main() { test06(); system("pause"); return 0; }

  Back to Reference- Return value

The const-modified constant function in the above section is generally used for variable output to prevent modifications to variables in this function

* this returns the object itself, which, combined with the reference type of the function, allows chain programming (top left), which is called all the time (for example, any number of <<< can be appended after a cout), but if the return value type is not a reference, it becomes the value of the return object (top right)

10. Friends

Friends are mainly used to solve the problem of inaccessible private classes, which are divided into:

1. The global function is the friend friend function name (); 2. Class is the friend class name; 3. The member function is the friend friend class name:: function name ();


using namespace std;
class Gay_friend {
    void visit_Person();

class Person {
    friend void visit();//Make this global function a friend
    friend class Gay_friend;//Class as Friend
    friend void Gay_friend::visit_Person();    //Member function as friend
    void visit_sittingroom(string name);
    void visit_bedroom(string name);

void Person::visit_sittingroom(string name) {
    cout << name << "Visiting the living room..." << endl;

void Person::visit_bedroom(string name) {
    cout<<name << "Visiting the bedroom..." << endl;


void Gay_friend::visit_Person(){
    string name = "friend class";
    Person p;

void visit() {//Global function as friend
    string name = "Global Functions";
    Person p;

int main() {
    Gay_friend gf;
    return 0;


11. Operator overloading

Operational operations that focus on custom data types

using namespace std;
class MyInteger {
    friend int operator+(MyInteger &p1, MyInteger &p2);
    friend ostream& operator<<(ostream &cout, MyInteger myint);
    MyInteger(int num, int age) {
        m_num = num;
        m_age = new int(age);
    MyInteger(int num) {
        m_num = num;
    ~MyInteger() {
        if (m_age != NULL) {//if age Opening up data in the heap releases memory in the heap
            delete m_age;//If no deep copy is made, the same memory will be freed repeatedly and an error will be reported.
            m_age = NULL;
    // Overload Relational Operators
    bool operator==(MyInteger &p) {
        if (this->m_age == p.m_age && this->m_num == p.m_num) {
            return true;
        return false;
    //Overloaded assignment operator
    MyInteger& operator=(MyInteger &p) {
        // You should first determine if there are any attributes in the heap area, and if so, release them first
        // That is p2=p1,Among them p2 There is already memory in the heap, so let's free its old memory before opening up a new one   
        if (m_age != NULL) {
            delete m_age;
            m_age = NULL;
        // deep copy
        m_age = new int(*p.m_age);
        // Return object itself
        return *this;//The object itself is returned here to implement the chain rule
    int *m_age;
    int m_num;


//Overload plus sign (binary operator overload is only possible outside of class)
int operator+(MyInteger &p1, MyInteger &p2) {
    return p1.m_num + p2.m_num;

// Overload Left Shift Operator
ostream& operator<<(ostream &cout, MyInteger myint) {
    cout << myint.m_num;
    return cout;

int main() {

    MyInteger p1(1, 18);
    MyInteger p2(1, 120);
    MyInteger p3(1, 1111);

    if (p1 == p2) { cout << "p1 p2 etc." << endl; }
    else { cout << "p1 p2 unequal" << endl; }
    cout << "p1+p2 Value of:" << p1 + p2 << endl;

    p3 = p2 =p1;//heavy load=Run after number
    cout << "p1:" << *p1.m_age << endl;
    cout << "p2:" << *p2.m_age << endl;
    cout << "p3:" << *p3.m_age << endl;
    return 0; 

Where the overload of the = sign is used to solve the problem of shallow copies resulting in shallow copies:m_age is a pointer type that opens up in the heap

Assume that if there are two objects, p1 and p2, and p1=p2 is executed, then m_of p1 is executed Age points to m_of P2 That piece of memory space age opened up, which is really correct in assignment, but there was an error when the object was destroyed

p2 destructs, frees up the space, p1 frees up again because it points here, and the program crashes


12. Type Conversion

c++ provides four types of conversion for other scenarios


static_cast is used for built-in data types, pointers with inheritance relationships, or references

using namespace std;

class Animal{};
class Cat{};
class Dog:public Animal{};

void test01(){
    int a=97;
    char c = static_cast<char>(a);

    Animal *ani=NULL;
    //Cat *cat = static_ Cast <Cat *> (ani);// Cannot convert without inheritance relationship
    Dog *dog = static_cast<Dog *>(ani);//Rotor class with parent pointer
    Animal animal;
    Animal &aniref = animal;
    Dog& d = static_cast<Dog&>(aniref);//Reference parent to rotator class


int main(){

    return 0;



reinterpret_cast Casts cast irrelevant pointer types, including function pointers, that can be converted

    Animal *animal;
    Cat *cat = reinterpret_cast<Cat*>(animal);
    //animal and cat can be transformed irrespective, unlike inheritance above


dynamic_cast transforms pointers or references (in the same way as static_cast) that have an inheritance relationship, and object type checks and static_cast are performed before the conversion Case comparison, dynamic_cast does security checks

For example, a child pointer to a parent pointer is safe, but a parent pointer to a rotator class pointer is unsafe, mainly because of concerns about crossing bounds





const_cast The underlying data type, pointer, reference, or object pointer. Function, cancel const,

    // 4.const_cast:Add or remove const
    int a = 10;
    const int& b =a;
    //b=20; // It can't be modified here
    int &c = const_cast<int &>(b);
    c = 20;
    const int *p1=NULL;
    int *p2 = const_cast<int *>(p1);//Eliminate const of p1 to p2
    const int *p4 = const_cast<const int*>(p2);//Add const to p3

13. Inline Functions

Function calls require additional overhead. If there are a few short, simple functions that are called frequently, they can consume a lot of stack space and can be defined as inline functions.

* Points to note:

1. Loop and switch statements are not allowed within inline functions;
2. The definition of an inline function must occur before the first call to an inline function.
3. The class in the class structure indicates that the function defined internally is an inline function.
inline void test02(int& a,int& b){
    int temp = a;
    a = b;
    b = temp;



14. Encapsulation, Inheritance, Polymorphism (C++ Object Oriented Features)

1. Packaging:

Encapsulation is a concept that binds data to functions that manipulate data in object-oriented programming. C++ supports encapsulation and data hiding (public, protected, private) by creating classes.

The only difference between struct and class in C++ is that the default access permissions are different

Strct defaults to public and class defaults to private

2. Inheritance:

Three ways to inherit ---> 1.public inherits 2.protected inherits 3.private inheritance The relationship after inheritance is as follows


Private properties of base classes are inaccessible regardless of inheritance

The order in which objects are created and destroyed when inheriting:
class Father{
        cout<<"Parent Construction"<<endl;
        cout<<"Parent Destruction"<<endl;
    int m_a;
    int m_b;
    int m_c;

class Son:public Father{
        cout<<"Subclass Construction"<<endl;
        cout<<"Subclass Destruction"<<endl;

Now is the problem? What is Son's memory model after inheritance?

When we look at sizeof(Son), we see that the result is 12, which means that the child inherits all the attributes from the parent (whether you are public or private), but the compiler hides them




Using the VS developer command prompt input: cl/d1 reportSingleClassLayoutSon "exp.cpp". You can see that son's memory model looks like this


--Diamond Inheritance Problem: A child class inherits more than two parent classes and at the same time inherits the same parent class, as shown in the figure



How to resolve: using virtual inheritance

class Animal{
    virtual void speak(){
    int m_age;

class Sheep:virtual public Animal{

class Tuo:virtual public Animal{

class SheepTuo:public Sheep,public Tuo{

void test17(){
    SheepTuo st;
    st.Sheep::m_age = 18;
    st.Tuo::m_age = 200;
    // The problem with this writing is that inheritance is repeated, and virtual inheritance should be used
    // Only one in memory exists at this time m_age Data, two parent classes pass through vbptr Point to this property in the subclass
    // At this point, all outputs are 200, because in fact everyone is a variable, that is, the subsequent assignment overrides the previous one


When you look at SheepTuo using the developer command prompt, you can see that it inherits a vbptr from Sheep and a vbptr from Tuo, respectively, that is, it actually inherits a pointer

virtual base pointer virtual base class pointer

vftable: virtual function table virtual function table

3. Polymorphism:

C++ polymorphism means that when a member function is called, different functions are executed depending on the type of object calling the function.

Polymorphic conditions: 1. There is an inheritance relationship, 2. Subclasses override virtual functions in parent classes

1. Compile-time polymorphism --> determine function address through function overload --> early binding --> compile-time

2. Runtime Polymorphism --> Determine Function Address by Virtual Function --> Late Binding --> Runtime

For example:

class Base_19{
    virtual void func()=0;//Declare as a pure virtual function
    // 1.Unable to instantiate object
    // 2.Subclasses of abstract classes must override pure virtual functions in the parent class, or they cannot instantiate objects
class Son_19 : public Base_19{
    virtual void func(){
void test19(){
    // Call parent pointer or reference to child object using polymorphic Technology
    Base_19 * base = new Son_19;

Fictitious Destruction: When resolving polymorphic use, if the child class has attributes open in the heap, the parent pointer cannot call the destructor code of the child class when it is released.

Pure fictitious destructions: The difference from fictitious destructions is that pure fictitious destructions are abstract classes and cannot instantiate objects.

It's a bit abstract, just look at the example and you can see that a fictitious destructor is declared below, and the program can run and invoke normally, but if you remove the virtual destructor, the result is as follows

class Animal_21{
    virtual ~Animal_21(){  //Declare a fictitious destructor
    virtual void speak()=0;//Declare a pure virtual function

class Cat_21 :public Animal_21{
    Cat_21(string name){
        m_name = new string(name);
        if(m_name!=NULL){//m_name is opened in the heap area,
            delete m_name;
            m_name = NULL;
    virtual void speak(){
        cout<<"Cat Talking"<<endl;
    string *m_name;
void test21(){
    Animal_21 *animal = new Cat_21("tom");//Writing polymorphism: parent pointer points to child class object
    delete animal;
    // A destructor for a subclass will not be called unless a virtual destructor is written


The biggest problem is that the program is finished before the cat's destructive call, but m_in cat Name was opened in the heap, causing a memory leak


15.C++ File Operation



// 1.Include header file#include<fstream>
    // 2.Create File Stream
    ofstream write_file;
    // 3.Specify how and where to open
    write_file.open("test.txt",ios::out);//Specifies to open in writing
    // 4.Write data
    write_file<<"1.this yes a test"<<endl;
    write_file<<"2.this yes a test"<<endl;
    write_file<<"3.this yes a test"<<endl;
    // 5.Close File
    // read file
    ifstream read_file;
        cout<<"Failed to open"<<endl;
        // Three ways to read data
        // 1.
        // char buf[1024] = {0};
        // while(read_file>>buf){
        //     cout<<buf<<endl;
        //     //This way, whenever a space is encountered, the carriage returns with a new line
        // }
        // 2.
        // char buf[1024] = {0};
        // while (read_file.getline(buf,sizeof(buf)))
        // {   
        //     cout<<buf<<endl;
        //     //The advantage of this approach is that the source file will wrap whenever it is read
        // }
        // 3.
        string buf;
        while (getline(read_file,buf))

16. Templates

1. Function templates:

Declare as template<typename T> or template<class T>

Call rules for function templates:

1. When both templates and normal functions can be called, ordinary functions are called first

void myprint(int a,int b){

template<class T>
void myprint(T a, T b){
     myprint(a,b);//Priority calls to normal functions

2. Templates can be forced to be invoked through an empty template parameter list

    //Force call to function template
3. Templates can be overloaded
    //heavy load
4. If the function template can match better, call the template first
    //When function templates match better, call function templates first
    //Compiler auto-push to
    char d = 'd';
    char e = 'e';
    myprint(d,e);//Because the normal function parameter is int,Function templates now match better

2. Class Templates

Membership functions in class templates are created only when they are invoked, and when using class templates, you need to specify the type that distinguishes them from function templates-->Function templates can be derived automatically


template<typename type1=string,typename type2=int>//Class template has default parameters, default type if not specified
class Person{
    Person_06(type1 name,type2 age){         this->name = name;         this->age = age;}     type1 name;     type2 age;     void show_Person(){         cout<<"name:"<<this->name<<" age:"<<this->age<<endl;}

The incoming data type must be specified when calling a class template member function

//The first style specifies the incoming type
void show(Person<string,int> p){

// Second Writing Parameter Templating
template<class T1,class T2>
void show(Person<T1,T2> &p){

// 3.Whole class Templating
template <class T>
void show(T &p){


Class templates and inheritance
When the parent inherited by a subclass is a template, you need to specify the type of T in the parent class. If you want the flexibility to specify the type of T in the parent class, the subclass also needs to become a template
template <class T>
class Base{  //Parent class is a class template
    T id;

template <class T1,class T2>
class Son:public Base<T2>{  //For flexibility of subclasses, subclasses are also defined as a class template
    Son(T1 name,T2 id){
        this->name = name;
        this->id = id;
    T1 name;


Reference material:

[1] static-knowing in C++ (zhihu.com)

[2] C++ Object Model Details - RunningSnail - Blog Park (cnblogs.com)

[3] (20 messages) Talking about c++ memory model_ PurpleDream's Blog - CSDN Blog_ c++ memory model

[4] Black Horse Programmer's Craftsmanship|C++ Tutorial From 0 to 1 Starter Programming, Learning Programming is no longer difficult_ Bell-Bell-Bell_ bilibili

Keywords: C++

Added by JREAM on Sat, 05 Feb 2022 19:34:32 +0200