C + + core programming

Keywords: C++ Algorithm camera tv

##0. Preface
Recently, when doing algorithm transplantation, I found that I had forgotten a lot about c + +, so I planned to pick it up again.
I feel shallow on paper. I never know that I have to practice it
It has always been the principle of my study and work. I prefer hands-on.
So I knocked the basic knowledge of c + + line by line, no matter how simple!
For future research camera framework source code, write algorithm transplantation framework to lay the foundation!

1. Memory partition model

c + + memory is divided into four areas:

  • Code area: it stores the binary code of the function body, which is managed by the operating system.

  • Global area: stores global variables, static variables and constants

  • Stack area: automatically allocated and released by the compiler to store function parameter values, local variables, etc.

  • Heap area: it is allocated and released by the programmer. If the programmer does not release it, it will be recycled by the operating system at the end of the program

Meaning of memory partition:
The data stored in different areas gives us different life cycles and gives us greater flexibility in programming.

1.1 before program operation

After the program is compiled, the exe executable program is produced. Before the program is executed, it is divided into
Code area:

deposit cpu Executed machine instructions
1.Sharing: the purpose is that for frequently executed programs, only one code is needed in memory.
2.Read only: prevent the program from being modified at will

Global area:

Global variables contain constant areas: string constants and other constants
 After the program ends, the system releases the data of the global area by itself
const Modified local variable(Local constant),Not in the global area, but in the stack area
int fun() {
 const int a =10;//Local constant
}

Summary:

  • c + + is divided into global area and code area before exe program runs
  • The code area is characterized by read-only and sharing
  • Global variables and static variable constants are stored in the global area
  • The const modified global variables (i.e. global constants) and string constants are stored in the constant area

1.2 after program operation

Stack area
Automatically allocate and release function parameters, local variables, etc. by the compiler
Note: without returning the address of local variables, the compiler will automatically release the data opened by the stack after the function is finished

Heap area
By the programmer and release respectively. If the programmer does not release, the system will release itself after the program ends. If the program does not end, the system will never release.

c + + mainly uses new to apply for memory in the heap

1.3 new usage

When applying for new, be sure to use delete to release

int *a = new int(10);
delete a;

int *b = new int [8];
delete [] b;//Array release to add []

2. Reference

2.1 basic use of references

**Function: * * alias variables
**Syntax: * * data type & alias = original name

int a =10;
int &b = a;
(In essence: int *const b = &a)

2.2 notes for reference

  • 1. The reference must be initialized
    int &b;// error
  • 2. The reference cannot be changed after initialization
int a =10;
int &b = a;

int c =20;

b = c;//Assignment operation instead of changing references

2.3 reference function parameters

**Function: * * when passing parameters to a function, you can use the reference technology to let the formal parameters modify the arguments
**Advantages: * * pointer modification arguments can be simplified

void swap(int &a,int &b) {
	int temp = a;
	a = b;
	b = temp;
}

2.4 reference function return value

Function: a reference can be used as the return value of a function

Note: do not return references to local variables

Usage: function call as lvalue

int& fun()
{
  static int a =10;
  return a;
}

int &ref = fun();

fun()= 100;//Function calls can be assigned as lvalues

2.5 nature of reference

Essence: the essence of reference is implemented internally in c + +. It is a pointer constant (the point is unchanged, and the value inside is variable)

//The compiler finds that this is a reference, and the conversion bit int * const ref = & A;
void func(int & ref) {
  ref = 100;//Ref is a reference, conversion bit * ref = 100
}

int main(){
  int a=10;

  int& ref = a;
  //Automatically convert to int * const ref = & A;
  //Pointer constants refer to unchangeable and changeable values, which also explains why references are unchangeable

  ref = 20;//If it is found to be a reference, it will be automatically converted to * ref =20
}

Conclusion: the c + + approach uses reference counting because of its convenient syntax. The essence of reference is pointer constant, but the compiler has done all pointer operations for us

const reference

**Function: * * constant reference is mainly used to modify formal parameters to prevent misoperation
const int & a;

int &ref =10;// This is wrong. The reference must refer to a legal memory. 10 in the constant area, const must be added when accessing

int &ref =10;//This is an error. The reference must refer to a valid piece of memory


const int &ref =10;//legitimate
//After adding const, the compiler changes the code to
/*
int temp =10;
const int &ref = temp;
*/

//Constant reference usage scenario: it is usually used to modify formal parameters to prevent function from changing values
void printValue(const int&a){
  //a=20; report errors
  print("a=%d",a);
}

3. Function improvement

3.1 default parameters of function

In c + +, function parameters can have default values.

Syntax: return value function name (parameter = default) {}

int func(int a,int b=1, int c =2) {

}
  • If there is a default parameter at a certain position in the formal parameter, there must be a default parameter from this position to the future, from left to right

  • If the function declaration has default parameters, the function implementation cannot have default parameters, otherwise an error will be reported: redefine the default parameters

int fun2(int a =10);//statement
int func2(int a =10){//realization
}
This will report an error

3.2 function occupancy parameters

The formal parameters of functions in c + + can have placeholder parameters, which are used for placeholder. This position must be filled when calling functions.

Syntax: return value function name (data type) {}

//Placeholder parameter - second parameter
void func(int a,int) {

}
//Placeholder parameters can also have default parameters
void func2(int = 10){

}

int main(){
 func(10,10);
}

3.3 function overloading

3.3.1 function overloading overview

**Function: * * function names can be the same to improve reusability

Function overload satisfies the condition

  • Under the same scope
  • Same function name
  • Function parameters have different types, numbers or orders

**Note: * * the return value of a function cannot be used as a condition for function overloading

void fun();
void fun (int a,float b)
void fun (float b,int a)
//Int fun (float B, int a) this will report an error, which is ambiguous
3.3.2 precautions for function overloading
  • Reference as overload condition
//1. Reference as overload condition
void func(int &a){ //int& a =10 ; wrongful

}

void func(const int &a){const int &a = 10 legitimate

}
These two are function overloads int and const int Calculate different types

int main(){
int a =10;
func(a);//Call the first void func (int & A),
//If void func (int &a) is not defined, the second one is called
func(10);//Call the second void func (const int & A)
}

  • Function overload encountered default parameter
void func(int a){ //int& a =10 ; wrongful

}
void func(int a,int b =10){
}

fun(10);//The compiler doesn't know which to call here

Here, the function will be ambiguous and error will be reported,
Generally, don't write default parameters when writing function overloads

4. Classes and objects

Everything is an object, including attributes and behaviors
Three characteristics of c + + object-oriented: encapsulation, inheritance and polymorphism

4.1 packaging

4.4.1 significance of packaging

Encapsulation is one of the three characteristics of c + + object-oriented
significance:

  • Take attributes and behaviors as a whole to express things in life
  • Control attributes and behaviors with permissions f

Meaning of encapsulation 1:
When designing classes, attributes and behaviors are written together to represent things

**Syntax: * * class class name {access rights: attribute / behavior};

Design a circle class

//PI
const double PI = 3.14;

class Circle
{
//Access rights
public:

//attribute
int r;//radius

//behavior
double calZC(){
  return 2*PI*r;
}


Circle c ;//object
c.r = 10;
c.calZC();

}

Meaning of encapsulation 2:
Control attributes and behaviors with permissions

There are three kinds of access rights
1.public: public permission
Members can be accessed inside the class and outside the class
2.protected: protected permission
Members can be accessed inside the class, but not outside the class
3.private: private permission
Members can be accessed inside the class, but not outside the class

4.1.2 differences between struct and class

In c + +, the only difference between struct and class is:
Different default access rights

  • struct default permission public
  • class default permission private
class C1
{
  int a;//private
};

struct C2 {
int  a ;//public
}

4.1.3 set member property to private

  • Advantage 1: set all properties to private, and you can control the read and write permissions yourself
  • **Advantage 2: * * for write permission, data validity can be detected

4.2 initialization and release of objects

4.2.1 constructors and destructors

Object initialization and release are two very important security issues.

The object does not use the initial state, and the consequences are unknown
If the object is not released after use, it will also cause difficult security problems

  • Constructor: initializes properties when an object is created
  • Destructor: releases resources when an object is destroyed
    Both functions are called automatically by the system!

**Constructor syntax: * * class name () {}
1. The constructor does not return a value and does not write void
2. The function name and class name are the same
3. The constructor has parameters and can be overloaded
4. When creating an object, the constructor is automatically called once

Destructor syntax:
1. The destructor does not return a value or write void
2. The destructor is the same as the class name, and the destructor is added before the name~
3. The destructor has no parameters and cannot be overloaded
4. The destructor will be called automatically before the object is destroyed

Class p{
 //Constructor
 p(){ }
  //Destructor
~p(){
}
};
4.2.3 classification and calling of constructors

Two classification methods:
According to parameters: parametric construction and nonparametric construction
By type: normal construction and copy construction

Three call modes:
bracketing
Display method
Implicit transformation method

class Person {
public:
  Person(){//Nonparametric structure
  }
  Person(int a){//Parametric structure
    age = a;
  }
//The above are all ordinary structures

  Person(const  Person &p){//copy construction 
    age = p.age;
  }

private: 
int age;
}


1.bracketing
Person p1;
Person p2(10);
Person p3(p2);

2.Display method
Person p1;
Person p2  = Person(10);
Person p3 = Person(p2);

Person(6);//It's an anonymous object
 Feature: after the execution of the current line, the system will immediately recycle anonymous objects

matters needing attention:
Do not use copy constructors to initialize anonymous objects
Person(p3);
The compiler will think Person(p3) == Person p3;



3.Implicit transformation method
Person p4 = 10;//Equivalent to Person p4 = Person(10);
Person p5 = p4;//Equivalent to Person p5 = Person(p4);
4.2.3 call timing of copy constructor
class Person{
public:
  Person(){
    Nonparametric structure
  }

  Person(int a ){
    Parametric structure
    age =a;
  }

  Person(const Person & p){
    copy construction 
    age = p.age;
  }

  ~Person(){
    Destructor
  }

private:
int age;
}

Three cases:

  • Initialize a new object with an already created object
void test(){
  Person p1(20);
  Person p2(p1);
}
  • Values are passed to function parameters
void doWork(Person p){//This is equivalent to Person p = my_p
  
}
void test2(){
    Person my_p;
    doWork(my_p);
}
* Returns a local object as a value
```c
Person doWork3(){
  Person p;
  return p;//Here, p will be released after execution, and the system will copy a temporary p back
}
void test(){
  Person p = doWrok3();
}
4.2.4 constructor calling rules

By default, the c + + editor adds three functions to a class

1. Default constructor (no parameter function body is empty)
2. Default destructor (nonparametric function body is empty)
3. Default copy constructor (copy values of all attributes)

Constructor rule:

  • If the user defines a parameterized construct, the c + + editor will not provide a default nonparametric construct, but will provide a default copy construct
  • If you define a copy constructor, c + + does not provide another constructor
  Person(const Person & p){
    copy construction 
    age = p.age;
  }

4.2.5 deep and light copies

  • Shallow copy: value copy
  • Deep copy: reapply a piece of memory space in the heap for copy operation
#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Person
{
public:
	Person()
	{
		cout<<"Person Default constructor "<<endl;
	}
	Person(int age,int height)
	{
		m_age = age;
		m_height = new int(height);
		cout<<"Person Parameterized constructor"<<endl;
	}
	
	//Shallow copy: the problem is that the heap is repeatedly released 
	Person(const Person &p)
	{
		cout<<"Person Shallow copy constructor call"<<endl;
		m_age = p.m_age;
		m_height = p.m_height;
	}
	
	//Deep copy
	Person(const Person &p)
	{
		m_age = p.m_age;
		m_height = new int(*p.m_height);
	}	 
	
	~Person()
	{
		cout<<"Person Destructor call,m_height address"<<m_height<<endl;
		if(m_height != nullptr)
		{
			cout<<"release person=%p"<<this<<" m_height ="<<*m_height<<endl;
			delete m_height;
			m_height = nullptr;
		}
		
	}

	int m_age;
	int *m_height;
};

void test()
{
	Person p1(18,180);
	cout<<"p1 ="<< (int*)&p1 << " "<<p1.m_age<<"  "<<*p1.m_height<<endl;
	Person p2(p1);
	cout<<"p2 ="<<(int*)&p2<< " "<<p2.m_age<<"  "<<*p2.m_height<<endl;
}

int main(int argc, char** argv) {
	test();
	return 0;
}

Summary: if the member variable has the ability to open up memory in the heap area, it is necessary to provide its own copy constructor to prevent the repeated release of heap memory in the shallow copy agent

4.2.6 initialization list

effect
c + + provides the syntax of initialization list to initialize attributes

**Syntax: * * constructor (): attribute 1 (value 1), attribute 2 (value 2) ·· {}

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Person
{
public:
	Person():m_a(10),m_b(20)
	{
		
	}
	
	Person(int a,int b):m_a(a),m_b(b)
	{
		
	}	
	int m_a;
	int m_b;
};

int main(int argc, char** argv) {
	Person p;
	cout<<p.m_a<<" "<<p.m_b<<endl;
	Person p2(30,40);
	cout<<p2.m_a<<" "<<p2.m_b<<endl;
	return 0;
}

4.2.7 class objects as members of classes

When constructing: when other class objects are members of this class, the objects of other classes are constructed first, and the object itself is constructed
Destruct: first destruct yourself, and then destruct other classes. (because the loading function is in the form of stack, last in, first out)

class Phone
{
public:
	Phone(string name):name(name)
	{
		cout<<"Phone Parameterized constructor call"<<endl;
		//this.name = name;
	}
	
	~Phone()
	{
		cout<<"Phone Destructor call"<<endl;		
	}
	string name;	
} ;

class Person
{
public:
	Person(string name,string p):name(name),p(p)
	{
		cout<<"Person Parameterized constructor call"<<endl;		
	}
	
	~Person()
	{
		cout<<"Person Destructor call"<<endl;		
	}
	string name;
	Phone p;	
};

4.2.8 static members

Add the static keyword in front of member functions and member variables to become static members.

Static members are divided into:

  • Static member variable
    • All objects share one piece of data
    • Allocate memory at compile time
    • Inner class declaration, outer class initialization
class A
{
public:
  static int m_a;//Intra class declaration
}
int A::m_a = 100;//static should be removed for out of class initialization
  • Static member function
    • All objects share the same function
    • Static member functions can only access static member variables
    • Private member functions or variables cannot be accessed outside the class
class Person
{
public:
	static void fun()
	{
		cout<<"Static member function"<<endl;
	//	m_a = 1;
		m_b = 2;
	}
	
	int m_a;
	static int m_b;

priviate:
static void fun2()//
{
}

} ;

void test()
{
	//1. Call through object 
	Person p;
	p.fun();
	//2. Call by class name
	Person::fun();

//Private cannot be accessed
//Person::fun2();
}

4.3 C + + object model and this pointer

4.3.1 member variables and member functions are stored separately

In c + +, member variables and member functions in a class are stored separately,
Only non static member variables belong to objects of a class

  • Empty objects occupy 1 byte of memory
    The c + + compiler allocates a byte space to each empty object to distinguish the memory occupied by the empty object.
class Person
{
	
} ;

void test()
{
	Person p;//Empty object
	cout<<sizeof(p)<<endl;
}

  • Only non static member variables belong to objects of a class
class Person
{
	int a;//The non static member variable belongs to the object of the class. At this time, p's memory is 4 bytes
	
	static int b;//Static member variables do not belong to class objects
	
	void fun();//Non static member functions do not belong to class objects
	
	static void fun2();//Static member functions do not belong to class objects 
	
} ;

void test()
{
	Person p;
	cout<<sizeof(p)<<endl;
}

4.3.2 concept of this pointer

The this pointer points to the object to which the called member function belongs
Whoever calls this, this points to which object

this is a pointer implicit in a non static member function

Purpose of this pointer:

  • When a formal parameter has the same name as a member variable, it can be distinguished by the this pointer
  • Return the object itself in the non static member function of the class. You can use return *this
class Person
{
public:
	Person(int age)
	{
		this->age = age;
	}
	
//Here, you need to return Person &. If you return Person, the system will create a temporary variable to return
	Person& addAge(Person &p)
	{
		this->age += p.age;
         //This points to the pointer to p2, while * this points to the p2 object itself
		return *this;
	}
	int age;
		
} ;

This points to the pointer to p2, while * this points to the p2 object itself

4.3.3 null pointer accessing member functions

c + + hollow pointers can also call member functions,
If you want to use this pointer, you should judge it to ensure the robustness of the code

class Person
{
public:
	void showName()
	{
		cout<<"this is Person class"<<endl;
	}	
	
	void showAge()
	{
		if(this == NULL)//Increase robustness 
			return;
		cout<<"age = "<<this->age<<endl;//p == null. Direct access here will crash 
	}
	
	int age;
};

int main(int argc, char** argv) {
	Person *p =NULL;
	p->showName();
	p->showAge();
	return 0;
}

4.3.4 const modifier member function

Constant function

  • A member function followed by the const keyword is called a constant function
  • Member properties cannot be modified within a constant function
  • After the keyword mutable is added to the member function, it can be modified in the constant function

Constant object:

  • Adding const before declaring an object is called a constant object
  • Constant objects can only call constant functions (because ordinary functions can change member variables, and constant objects are not allowed to modify member variables)
class Person
{
public:
	//Constant function
	//Add const after the member function to modify the point of this, and the value pointed by the pointer cannot be modified. Here this = const person * const this  
	void showPerson() const
	{
		//this = (Person * const this) is essentially a pointer constant. The pointing of the pointer cannot be modified, and the pointing content is variable 
		//this->m_ a = 100; No change allowed 
		this->m_b =100; 
	} 
	
	void fun()
	{
		//You can modify the value of member variables, such as m_a =10;
	} 
	
	int m_a;
	mutable int m_b;//mutable variable can modify the value even in constant functions 
};

//Constant object
void test()
{
	const Person p ;//Add const in front of the object to become a constant object
	//p.m_a = 100;  Constant objects are not allowed to change any value 
	p.m_b = 100;
	//Constant objects can only call constant functions
	p.showPerson(); 
	//p.fun();// Constant objects cannot call ordinary member functions, because ordinary member functions can modify member variables, and constant objects are not allowed to modify 
} 

4.4 friends

effect:
Let a function or class access private members in another class
friend keyword

Three implementations of friends:

  • Global function as friend
class MyHome
{
	//Global function as friend
	friend void  goodGay(MyHome &m);
public:
	MyHome():m_livingRoom("a living room"),m_bedRoom("bedroom") 
	{
			
	}	
	string m_livingRoom;//a living room
	 
private:
	string m_bedRoom;//bedroom 
} ;

//Global function
void goodGay(MyHome &m)//Here, it is equivalent to myhome * const M = & MH; 
{
	cout<<"Good friends are visiting:"<<m.m_livingRoom<<endl;
	cout<<"Good friends are visiting:"<<m.m_bedRoom;
} 
int main(int argc, char** argv) {
	MyHome mh;
	goodGay(mh);
	return 0;
}
  • Class as friend
class Home
{
public:
	friend class GoodGay;
	Home():m_livingRoom("a living room"), m_bedRoom("bedroom")
	{
		
	}
public:
	string m_livingRoom;
private:
	string m_bedRoom;
};

class GoodGay
{
public:
	GoodGay()
	{
		h = new Home;
	}
	void visit()
	{
		cout<<"Good friends are visiting:"<< h->m_livingRoom<<endl;
		cout<<"Good friends are visiting:"<< h->m_bedRoom<<endl;
	}	
private:
	Home *h;
};
  • Member function as friend
class GoodGay;

class Home
{
//Member function as friend
	friend void GoodGay::visit(); 
public:
	Home():m_livingRoom("a living room"), m_bedRoom("bedroom")
	{
		
	}
public:
	string m_livingRoom;
private:
	string m_bedRoom;
};

class GoodGay
{
public:
	GoodGay()
	{
		h = new Home;
	}
	void visit()
	{
		cout<<"Good friends are visiting:"<< h->m_livingRoom<<endl;
		cout<<"Good friends are visiting:"<< h->m_bedRoom<<endl;
	}
	
private:
	Home *h;
};

void test()
{
	GoodGay g;
	g.visit();
}

4.5 heavy load

ps: operator overload skip

4.6 succession

Benefits of inheritance
Reduce duplicate code

4.6.1 basic syntax of inheritance

Syntax:
Class subclass: inheritance method parent class
Subclasses are also called derived classes
The parent class also becomes the base class

class BaspePage
{
public:
	void header()
	{
		cout<<"Home open class login registration"<<endl;
	}
	void footer()
	{
		cout<<"Help center, join us"<<endl;
	}
} ;

class Jave : public BaspePage
{
public:
	void content()
	{
		cout<<"This is JAVA course"<<endl;
	}	
};
int main(int argc, char** argv) {
	Jave j;
	j.header();
	j.content();
	j.footer();
	return 0;
}

4.6.2 mode of inheritance

There are three ways of inheritance:

  • Public inheritance
  • Protect inheritance
  • Private inheritance

class Father
{
public:
	Father():a(1),b(1),c(1)
	{
		
	} 
public:
	int a;
protected:
	int b;
private:
	int c;	
};

class Son1:public Father
{
public:
	void fun()
	{
		a= 10; 
		b= 20;
		//c= 30;
	} 
};
void test01()
{
	Son1 s;
	s.a = 100;
	//s.b = 50;  Cannot access outside the protection permission class 
}

4.6.3 object model in inheritance

Question: which members inherited from the parent class belong to the subclass object?
Private members will also be inherited by subclasses, but they are hidden by the compiler and cannot be accessed

class Base
{
public:
	int a;
protected:
	int b;
private:
	int c;//Private members will also be inherited by subclasses, but they are hidden by the compiler and cannot be accessed 
};
class Son:private Base
{
public:
	int d;
};


int main(int argc, char** argv) {
	Son s;
	cout<<sizeof(s)<<endl;//size = 16 
	return 0;
}

4.6.4 order of construction and Deconstruction in inheritance

After a subclass inherits the parent class, the construction of the parent class will also be called when creating a subclass object.

First construct the parent class, and then construct the child class. The deconstruction is the opposite: first construct the child class, and then the parent class

class Base
{
public:
	Base()
	{
		std::cout<<"Base Default constructor for"<<endl;
	}
	~Base()
	{
		std::cout<<"Base Destructor for"<<endl;
	}	
};

class Son: public Base
{
public:
	Son()
	{
		std::cout<<"Son Default constructor for"<<endl;		
	}
	~Son()
	{
		std::cout<<"Son Destructor for"<<endl;		
	}
};

void test()
{
	Son s;
} 

4.6.5 handling method of members with the same name in inheritance

Question: when a member with the same name appears between a subclass and a parent class, how can you access the data with the same name of the subclass or parent class through the subclass object?

  • You can access the member with the same name in the subclass directly
  • To access a member with the same name as the parent class, you need to add a scope

Summary:

  • 1. Subclass objects can directly access members with the same name in subclasses
  • 2. The subclass object plus scope can access the member with the same name as the parent class
  • 3. When the subclass and the parent class have member functions with the same name, the subclass will hide all functions with the same name in the parent class. You need to add scope to access the functions with the same name in the parent class
class Base
{
public:
	Base()
	{
		m_a = 100;
	}	
	
	void fun()
	{
		cout<<"Base - fun()"<<endl;
	}
	void fun(int a)
	{
		cout<<"Base - fun(int a)"<<endl;
	} 	
	
	int m_a;
};

class Son : public Base
{
public:
	Son()
	{
		m_a = 200;
	}
	
	void fun()
	{
		cout<<"Son - fun()"<<endl;
	} 	
	
	int m_a;
	
};

void test()
{
	Son s;
	cout<<"Son  Lower m_a = "<<s.m_a<<endl;
	//To access a member with the same name in the parent class through a subclass object, you need to add the scope Base 
	cout<<"Base Lower m_a = "<<s.Base::m_a<<endl;	 
}

void test2()
{
	Son s;
	s.fun(10);
	//To access a member with the same name in the parent class through a subclass object, you need to add the scope Base 
	s.Base::fun();
	
	//When a member function with the same name as the parent class appears in a subclass, the subclass will hide all member functions with the same name in the parent class 
	//A hidden member function with the same name can only be accessed through the scope 
	s.Base::fun(10);	
} 

4.6.6 processing method of inheriting static members with the same name

Question: how do static members with the same name in inheritance access on subclass objects?

Static members and non static members have the same name and are handled in the same way

  • You can access the member with the same name in the subclass directly
  • To access a member with the same name as the parent class, you need to add a scope
	//Access by object 
	Son s;
	cout<<s.m_a<<endl;
	cout<<s.Base::m_a<<endl;
	//Access by class name 
	cout<<Son::m_a<<endl;
    //The first:: represents access through the class name, and the second:: represents access under the scope of the parent class
	cout<<Son::Base::m_a<<endl;

Summary: the processing method of static members with the same name is exactly the same as that of non static members, except that there are two access methods (through object and class name)

4.6.7 multi inheritance syntax

Running a class in c + + inherits multiple classes

Syntax: class subclass: inheritance method parent class 1, inheritance method parent class 2···
Multiple inheritance may cause members with the same name to appear in the parent class, which needs to be distinguished by scope

Multi inheritance is not recommended in c + + development

class A
{
public:
	A():m_a(100)
	{
		
	}
	int m_a;
};

class B
{
public:
	B():m_a(200)
	{
		
	}
	int m_a;
};

class C : public A, public B
{
public:
	C()
	{
		m_c = 300;
	}
	
	int m_c;
};
int main(int argc, char** argv) {
	C c;
    //When a member with the same name appears in the parent class, scope differentiation is required
	cout<<c.A::m_a<<" "<<c.B::m_a<<" "<<c.m_c<<endl;
	return 0;
}

4.6.8 diamond inheritance

Concept:
2 subclasses inherit the same parent class
Another class inherits 2 subclasses
This inheritance is called diamond inheritance, or diamond inheritance

class Animal
{
public:
	int m_Age;
};
//Virtual keyword is added before inheritance, which becomes virtual inheritance
//At this time, the public parent class Animal is called the virtual base class 
class Sheep : virtual public Animal{};//sheep
class Camel : virtual public Animal{};//camel
class Alpaca : public Sheep , public Camel{};//Alpaca 
int main() {
	Alpaca a;
	a.Sheep::m_Age = 100;
	a.Camel::m_Age = 200;
	cout<<"a.Sheep::m_Age ="<<a.Sheep::m_Age<<endl;
	cout<<"a.Camel::m_Age ="<<a.Camel::m_Age<<endl;
	cout<<"am_Age ="<<a.m_Age<<endl;//All three prints are 200, and there is only one copy of data
	return 0;
}

Summary:

  • The main problem caused by diamond inheritance is that subclasses inherit multiple copies of the same data, resulting in a waste of resources.
  • Using virtual inheritance to solve diamond inheritance problem
  • The essence of virtual inheritance is to inherit pointers and access the same data (m_Age) through pointers

4.7 polymorphism

Polymorphism is one of the three characteristics of C + + object-oriented

4.7.1 basic concept of polymorphism

Polymorphisms fall into two categories:

  • Static polymorphism: function overloading and operator overloading belong to static polymorphism and reuse function names
  • Dynamic polymorphism: derived classes and virtual functions implement runtime polymorphism

Difference between static polymorphism and dynamic polymorphism:

  • Statically polymorphic function address early binding - the function address is determined at the compilation stage
  • Dynamic polymorphic function address late binding - function address determined at run time

Static polymorphism

class Animal
{
public:
	void speak()
	{
		cout<<"Animals are talking"<<endl; 
	}	
} ;
class Cat : public Animal
{
public:
    //Override: the return value of the function is exactly the same as the parameter list
	void speak()
	{
		cout<<"The cat is talking"<<endl;
	}
};
//Address early binding determines the function address at the compilation stage
//No matter what is passed, only the functions of the parent class will be called 
void doSpeak(Animal &a)
{
	a.speak();
}

void test()
{
	Cat c;
	doSpeak(c);
}

int main(int argc, char** argv) {
	test();//Output: the animal is talking 
	return 0;
}

Dynamic polymorphism

class Animal
{
public:
    //Add virtual to become a virtual function, and you can bind late. Subclass functions can add virtual or not
	virtual void speak()
	{
		cout<<"Animals are talking"<<endl; 
	}	
} ;

Override: the return value of the function is exactly the same as the parameter list
Overload: the function parameter list is different and the return value is the same

Summary:
Satisfaction conditions of dynamic polymorphism

  • 1. Inheritance
  • 2. The subclass overrides the virtual function of the parent class

Use of dynamic polymorphism
The pointer or reference of the parent class to execute the child class object

class A
{
public:
   int fun(){}
}
here sizeof(A)= 1 
class A
{
public:
   virtual int fun(){}
}
here sizeof(A)= 4,Because plus virtual ,fun It becomes a pointer(Pointers are 4 bytes)vfptr:Virtual function pointer

4.7.2 polymorphic case - calculator

Common code implementation calculator

//Common code implementation calculator
class NomalCal
{
public:
	int getResutl(int oper)
	{
		switch(oper)
		{
			case '+' :
				return m_a + m_b;
				break;
			case '-' :
				return m_a - m_b;
				break;
			case '*' :
				return m_a * m_b;
				break;
			//If you want to extend the function: Division, you need to modify the source code
			//Open close principle is advocated in development: open the extension and close the modification 
			default:
				return 0;			
		}	
	}	
	int m_a;
	int m_b;
} ;

void test1()
{
	NomalCal nc;
	nc.m_a = 10;
	nc.m_b = 10;
	cout<<nc.m_a<< " + " <<nc.m_b<<" = "<<nc.getResutl('+')<<endl;
}

Polymorphic implementation calculator

//Polymorphic implementation
class BaseCal
{
public:
	virtual int getResult(){return 0;}
	int m_a;
	int m_b;
} ;

class AddCal : public BaseCal
{
	int getResult()
	{
		return m_a+m_b;
	}	
};

Other functions continue to be added, such as subtraction

void test2()
{
	//Polymorphic usage conditions: parent class pointer or reference points to objects such as 
	BaseCal *bc = new AddCal;
	bc->m_a = 20;
	bc->m_b = 10;
	cout<<bc->m_a<< " + " <<bc->m_b<<" = "<<bc->getResult()<<endl;
	delete bc;//Remember to release 
}

Advantages of polymorphism:

  • Clear code structure
  • Strong readability
  • It is conducive to the expansion and maintenance in the early and later stages, and conforms to the opening and closing principle

4.7.3 pure virtual functions and abstract classes

In polymorphism, usually the virtual function in the parent class is meaningless and mainly calls the overridden function of the child class.

Therefore, we can change the virtual function to pure virtual function

Syntax: virtual return value type function name (parameter list) = 0

When there is only one pure virtual function in a class, the class is also called an abstract class

Characteristics of abstract classes:

  • Unable to instantiate object
  • Subclasses must override pure virtual functions in abstract classes, otherwise they also belong to abstract classes
class Base//Abstract class: as long as there is a pure virtual function in the class 
{
public:
	//Pure virtual function 
	virtual void fun() = 0;	
} ;
class Son : public Base
{
public:
	virtual void fun(){}
};

4.7.4 case 2 - making drinks

1. Abstract class of tea

class AbsDrinKing
{
public:
	//1. Boiling water 
	virtual void boil() = 0;
	//2. Brewing
	virtual void brew() = 0;
	//3. Pour into the cup
	virtual void pourInCup() = 0; 
	//4. Add auxiliary materials
	virtual void putSomething() = 0;
	
	void makeDrink()
	{
		boil();
		brew();
		pourInCup();
		putSomething();
	} 
};

2. Make coffee

class CofferDrink : public AbsDrinKing
{
	//1. Boiling water 
	virtual void boil()
	{
		cout<<"Cook Coffee"<<endl;
	};
	//2. Brewing
	virtual void brew()
	{
		cout<<"make coffee"<<endl;
	}
	//3. Pour into the cup
	virtual void pourInCup()
	{
		cout<<"Pour the coffee into the cup"<<endl;
	} 
	//4. Add auxiliary materials
	virtual void putSomething()
	{
		cout<<"Add sugar"<<endl;
	}
};

3. Making milk tea is the same
Omit···
4. Make function

void doWork(AbsDringKing *abs)
{
  abs->makeDrink();
}

4.7.5 virtual destruct and pure virtual destruct

When polymorphism is used, if an attribute in a subclass is opened to the heap, the parent class pointer cannot call the destructor code of the subclass when it is released.

Solution: change the destructor of the parent class to virtual destructor or pure virtual destructor

Virtual destructor and pure virtual destructor have the following commonalities:

  • It can solve the problem of releasing subclass objects from parent class pointers
  • All need to have specific function implementation

Difference between virtual destruct and pure virtual destruct:

  • If it is a pure virtual destructor, the class belongs to an abstract class and cannot instantiate an object, but a virtual destructor can!

Virtual destructor syntax:
virtual class name () {}

Pure virtual destructor syntax:
virtual class name () = 0;
Write an implementation outside the class
Class name:: ~ class name () {}

Possible memory leaks

terms of settlement:
1. The parent destructor plus virtual becomes a virtual destructor

class Animal
{
public:
	Animal(){cout<<"Animal constructor call "<<endl;}
	virtual ~Animal(){cout<<"Animal Virtual destructor call"<<endl;}//Virtual deconstruction
	virtual void speak() = 0; 
};

2. Pure virtual deconstruction

class Animal
{
public:
	Animal(){cout<<"Animal constructor call "<<endl;}
	virtual ~Animal() = 0;//Pure virtual deconstruction 
	virtual void speak() = 0; 
};
Animal::~ Animal()
{
	//If the parent class also applies for heap memory, it can be released here 
	cout<<"Animal Pure virtual destructor call"<<endl;
} 

Summary:

  • 1. Virtual destruct and pure virtual destruct are used to solve the situation of releasing subclass objects through parent class pointers
  • 2. If there is no heap data in the subclass, you can not write virtual destruct or pure virtual destruct
  • 3. Classes with pure virtual functions also belong to abstract classes

4.7.6 case 3 - computer assembly

//Abstract parts
//1. Abstract CPU
class CPU
{
public: 
	virtual void cal() = 0;
};
//2. Abstract graphics card
class VideoCard
{
public: 
	virtual void display() = 0;
};
//3. Abstract memory
class Memory
{
public: 
	virtual void storage() = 0;	
} ;

//Computer
class Computer
{
public:
	Computer(CPU *cpu,VideoCard *vc,Memory * mem)
	{
		m_cpu = cpu;
		m_vc = vc;
		m_mem = mem;
		cout<<"Computer Constructor"<<endl;
	}
	
	~ Computer()
	{
		if(m_cpu!=NULL)
		{
			delete m_cpu;
			m_cpu = NULL;
		}
		if(m_vc!=NULL)
		{
			delete m_vc;
			m_vc = NULL;
		}
		if(m_mem!=NULL)
		{
			delete m_mem;
			m_mem = NULL;
		}
		cout<<"Computer Destructor releases resources"<<endl; 
	} 
	
	void doWork()
	{
        //The parent class pointer calls the child class object
		m_cpu->cal();
		m_vc->display();
		m_mem->storage();
	}
private:
	CPU *m_cpu;
	VideoCard *m_vc;
	Memory *m_mem;
};

//intel computer 
class IntelCPU : public CPU
{
public:
	void cal(){cout<<"Intel cpu Work"<<endl;}
};
class IntelVideoCard : public VideoCard
{
public:
	void display(){cout<<"Intel The graphics card is working"<<endl;;}	
};
class IntelMemory : public Memory
{
public:
	void storage(){cout<<"Intel Memory is working"<<endl;}	
};
//Apple omits***
void test()
{
	//First computer
	IntelCPU * ic = new IntelCPU;
	IntelVideoCard *ivc = new IntelVideoCard;
	IntelMemory *imem = new IntelMemory;

	Computer *com1 = new Computer(ic,ivc,imem);
	com1->doWork();
	delete com1; 
} 

int main(int argc, char** argv) {
	test();
	return 0;
}

5. File operation

There are two types of documents:
**1. Text file: * * the text is stored in the computer in ASCII code
**2. Binary file: * * text is stored in binary form in the computer

Header file:

Three categories of operation documents:
1.ofstream: write operation
2.ifstream: read operation
3.fstream: read / write operation

5.1 text documents

5.1.1 writing documents

Write file steps:
1. Include header file
#include
2. Create a flow object
ofstream ofs;
3. Open the file
ofs.open("file path", opening method)
4. Write data
Ofs < < "data";
5. Close the file
ofs.close();

How files are opened:

Open modeexplain
ios::inread
ios::outwrite
ios::ateInitial location: end of file
ios::appWrite file in append mode
ios::truncIf the file exists, delete it before creating it
ios::binaryBinary form
//Text file write file
void test()
{
	ofstream ofs;
	ofs.open("test.txt",ios::out);
	ofs<<"Zhang San 18";
	ofs.close(); 
} 

5.1.2 document reading

To read a file:
1. Include header file
#include
2. Create a flow object
ifstream ifs;
3. Open the file
ifs.open("file path", opening method)
4. Write data
Four ways to read;
5. Close the file
ifs.close();

void test()
{
	ifstream ifs;
	ifs.open("test.txt",ios::in);
	if(!ifs.is_open())
	{
		cout<<"File open failed"<<endl;
		return;
	}
	//Method 1: read data
//	char buf[1024] = {0};
//	while(ifs >> buf) 
//	{
//		cout<<buf<<endl;
//	}
	//Method 2: read data
//	char buf[1024] = {0};
//	while(ifs.getline(buf,sizeof(buf)))
//	{
//		cout<<buf<<endl;
//	} 
	//Method 3: read data
//	string buf;
//	while(getline(ifs,buf))
//	{
//		cout<<buf<<endl;
//	}
	//Mode 4: read data
	char c;
	while((c = ifs.get())!=EOF)
	{
		cout<<c;
	}
	ifs.close();
}

5.2 binary files

Read and write files in binary mode,
The opening method should be specified as ios::binary

5.2.1 writing files in binary mode

class Person
{
public:
	char m_Name[64];
	int m_age;	
} ;

void test()
{
	//1. Import header file #include < fstream >
	
	//2. Create a flow object
	ofstream ofs;//Or ofs("person.txt",ios::out|ios::binary); 
	//3. Open the file
	ofs.open("person.txt",ios::out|ios::binary);
	//4. Writing documents 
	Person p = {"Zhang San",18};
	ofs.write((const char*)&p,sizeof(Person));
	//5. Close the file
	ofs.close(); 
}

5.2.2 reading files in binary mode

Reading files in binary mode mainly uses the member function read of stream object
Function prototype: istream & read (char * buffer, int len);

class Person
{
public:
	char m_Name[64];
	int m_age;	
} ;

void test()
{
	//1. Import header file
	
	//2. Create a flow object
	ifstream ifs;
	//3. Open the file
	ifs.open("person.txt",ios::in);
	if(!ifs.is_open())
	{
		cout<<"File opening failed!"<<endl;
		return;
	}
	// 4. Reading documents
	Person p;
	ifs.read((char *)&p,sizeof(Person)); 
	cout<<p.m_age<<" "<<p.m_Name<<endl; 	 
}

Continue to be a salted fish ( ̄)  ̄)!

Stay hungry,Stay foolish!

Posted by Leshiy on Tue, 23 Nov 2021 17:26:52 -0800