Class and object - object characteristics - separate storage of member variables and member functions

0 24
Class and object - static member#include <iostream> using namespace std;...

Class and object - static member

#include <iostream>
using namespace std;
class Person {
public:
	//Static member function
	static void func() {
		m_A = 100;//Static member functions can access static member variables
		//m_B = 200;//Static member functions cannot access non-static member variables, and it is impossible to distinguish which object's
		cout << "static func call" << endl;
	
	static int m_A;//Static
	int m_B;//Non-static
	
	//Static member functions also have access privileges
private:
	static void func2() {
		cout << "static void func2 call" << endl;
	
};
int Person::m_A = 0;
void test01() {
	//Accessed through object
	Person p;
	//Access through the class
	p.func();
	Person::func();
	
	//Person::func2(); The private static member function cannot be accessed outside the class
};
int main() {
	test01();
	return 0;

Class and object - object characteristics - separate storage of member variables and member functions

#include <iostream>
using namespace std;
class Person {
public:
	int m_a;//Non-static member variable, belongs to the object of the class
	static int m_b;//Static member variable, does not belong to the object of the class
	void func(){}//Non-static member function, does not belong to the object of the class
	static void func2(){}//Static member function, does not belong to the object of the class
};
 
void test01() {
	/*person p;
	cout << "size of p=" << sizeof(p) << endl;*/
	//The C++ compiler will allocate a byte of space for each empty object (for example, to distinguish the memory position occupied by an empty object), and each empty object should also have a unique memory address
};
void test02() {
	Person p;
	cout << "size of p=" << sizeof(p) << endl;

 
int main() {
	test02();
	return 0;

Class and object - object characteristics - usage of this pointer

Each non-static member function will only generate one function instance, which means that multiple objects of the same type will share a piece of code
So the question is: How does this piece of code distinguish which object calls itself?

C++ solves the above problem by providing a special object pointer, the this pointer. The this pointer points to the object that owns the member function being called

Class and object - object characteristics - separate storage of member variables and member functions

The this pointer is an implicit pointer in every non-static member function
The this pointer does not need to be defined; it can be used directly

The usage of the this pointer:
1. When the formal parameter and member variable have the same name, you can use the this pointer to distinguish
2. In non-static member functions of a class, you can return the object itself using return *this

#include <iostream>
using namespace std;
//Resolves name conflict
//Return the object itself with *this
class Person {
public:
	Person(int age) {
		this->age = age;//this pointer points to the object of the called function
	
	Person& Personage(Person& p) {
		this->age += p.age;
		//this points to the pointer of p2, and *this points to the object itself p2
		return *this;
	
	int age;
};
 
void test01() {
	Person p1(18);
	cout << "p1's age is: " << p1.age << endl;

void test02() {
	Person p1(10);
	Person p2(10);
	//p2.Personage(p1);
	p2.Personage(p1).Personage(p1).Personage(p1);//chained programming idea
	cout << "p2's age is: " << p2.age << endl;

 
int main() {
	//est01();
	test02();
	system("pause");
	return 0;

Class and object - object characteristics - empty pointer access member function

In C++, empty pointers can also call member functionsfunctionof, but also pay attention to whether it has been usedthis pointer.

If this pointer is used, it needs to be judged to ensure the code'sRobustness.

#include <iostream>
using namespace std;
//Empty pointer calls member function
class Person {
public:
	void showclassname() {
		cout << "this is person class" << endl;
	
	void showpersonage() {
		//The reason for the error without adding if is that the pointer passed in is NULL
		if (this == NULL) {
			return;
		
		cout << "age=" << m_Age << endl;
	
	int m_Age;
};
 
void test01() {
	Person* p = NULL;
	p->showclassname();
	p->showpersonage();

void test02() {
	

 
int main() {
	test01();
	test02();
	system("pause");
	return 0;

Class and object - object characteristics - const modifies member functions

Constant function:
MemberfunctionAfter adding const, we call this function a constant function
Member properties cannot be modified within a constant function
Add when declaring member propertiesKeywordAfter adding mutable, you can still modify it in a constant function

Constant object:
Add before declaring an objectconstThis object is called a constant object
Only constant functions can be called by a constant object

#include <iostream>
using namespace std;
//constant function
class Person {
public:
	//this pointer's essence is a pointer constant; the pointer's direction cannot be modified
 
	void showPerson()const//equals const Person*const this pointer points to a value that cannot be modified 
	{
		this->m_B = 100;
		//m_A = 100;
		//this=NULL; // The this pointer cannot modify the pointer's direction
	
 
	void func()
	{
	
 
	int m_A;
	mutable int m_B; // Special variable, can be modified even in constant functions
};
void test01() {
	Person p;
	p.showPerson();
	cout << "m_B: " << p.m_B << endl;

 
//Constant object
void test02() {
	const Person p; // Add const before the object to become a constant object
	//p.m_A = 100; cannot be modified
	//p.m_B = 100; can be modified
	//Constant object can only call constant functions
	//p.func(); cannot be called //Constant object Cannot call the ordinary member function, because the ordinary member function can modify the properties

 
int main() {
	test01();
	test02();
	system("pause");
	return 0;

Class and object - Object characteristics - Deep and shallow copy

Deep and shallow copyIt is a classic interview question and also a common pitfall
Shallow copy: Simple assignment copy operation
Deep copy: Reallocate space in the heap and perform copy operations

#include <iostream>
using namespace std;
class person{
public:
person() {
cout << "Default constructor" << endl;

person(int age,int high) {
m_age = age;
m_High = new int(high);
cout << "Parameterized constructor" << endl;
 

person(const person& p) {
cout << "Copy constructor" << endl;
m_age = p.m_age;
m_High = new int(*p.m_High); // If no new space is allocated, the delete will be called repeatedly

~person(){
if (m_High != NULL) {
delete m_High;
m_High = NULL;

cout << "Destructor call" << endl;

int m_age;
int* m_High;
};
void test01() {
person p1(18,160);
cout << "p1's age is: " << p1.m_age << "height is: " << *p1.m_High << endl;
person p2(p1);
cout << "p1's age is: " << p2.m_age << "height is: " << *p2.m_High << endl;

int main() {
test01();
system("pause");
return 0;

Class and object - C++ operator overloading

1. Plus operator

Function: Implement two customData typeAddition operation.

#include <iostream>
using namespace std;
 
//Overloading the plus operator
class Person{
public:
	//1. Member function overloading of +
	/*Person operator +(Person &p) {
		Person temp;
		temp.m_A = this->m_A + p.m_A;
		temp.m_B = this->m_B + p.m_B;
		return temp;
	}*/
	int m_A;
	int m_B;
};
 //2. Global function overloading of + 
Person operator+(Person& p1, Person& p2) {
	Person temp;
	temp.m_A = p1.m_A + p2.m_A;
	temp.m_B = p1.m_B + p2.m_B;
	return temp;

 
 
void test01() {
	Person p1;
	p1.m_A = 10;
	p1.m_B = 10;
	Person p2;
	p2.m_A = 10;
	p2.m_B = 10;
//Essence of member function overloading call
//Person p3=p1.operator(p2);
 
//Essence of global function overloading call
//Person p3=operator(p1,p2);
 
	Person p3 = p1 + p2;
	cout << "p3.m_A=" << p3.m_A << endl;
	cout << "p3.m_B=" << p3.m_B << endl;

 
 
 int main() {
	test01();
	system("pause");
	return 0;

2. Overloading the left shift operator

Function: Can output custom data types

#include <iostream>
using namespace std;
 
//Overloading the left shift operator
class Person{
	friend ostream& operator << (ostream& cout, Person& p);
public:
	Person(int a,int b):m_A(a),m_B(b){}
private:
	//Cannot use member function to overload the left shift operator
	/*void operator<<() {
	}*/
	int m_A;
	int m_B;
};
 //Using a global function to overload the left shift operator
ostream & operator << (ostream &cout, Person &p) //Essentially operator<<(cout,p) simplified as cout<<p
{
	cout << "m_A=" << p.m_A << "m_B=" << p.m_B ;
	return cout;

void test01() {
	Person p(10,10);
	cout << p << endl;

 
 int main() {
	test01();
	system("pause");
	return 0;

3. Overloading the increment operator

#include <iostream>
using namespace std;
 
//Overloading the increment operator
 
//Custom type definition
class Myinteger {
	friend ostream& operator<<(ostream& cout, Myinteger myint);
public:
	Myinteger() {
		m_Num = 0;
	
	
	// Overload the prefix ++ operator
	Myinteger& operator++()///Cannot remove the & before operator 
	{
		m_Num++;
		// Return the current object again
		return *this;
	
	
	// Overload the postfix ++ operator
	Myinteger operator++(int)//int represents a placeholder parameter, which can be used to distinguish between prefix and postfix
	{
		// Record the current result first
		Myinteger temp = *this;
		// Post-increment
		m_Num++;
		// Finally, return the recorded result
		return temp;
	
 
private:
	int m_Num;
};
 
// Overload the left shift operator
ostream& operator<<(ostream& cout, Myinteger myint) {
	cout << myint.m_Num;
	return cout;

 
void test01() {
	Myinteger myint;
	cout << ++(++myint) << endl;
	cout << myint << endl;

void test02() {
	Myinteger myint;
	cout << myint++ << endl;
	cout << myint << endl;

 int main() {
	test01();
	test02();
	system("pause");
	return 0;

4. Assignment operator

C++CompilerAt least add 4 functions to a class
1. DefaultConstructor(No-argument, the function body is empty)

2. DefaultDestructor(No-argument, the function body is empty)

3. DefaultCopy constructor, copy the value of the properties

4. Assignment operatoroperator=, copy the value of the properties

If a class has properties pointing to the heap area, deep and shallow copy issues may occur during assignment operations

#include <iostream>
#include <string>
using namespace std;
 
// Overload the assignment operator
 
class Person {
public:
	Person(int age) {
		m_Age = new int(age);
	
	~Person() {
		if (m_Age != NULL) {
			delete m_Age;
			m_Age = NULL;
		
	
	// Overload the assignment operator
	Person &operator=(Person& p) {
		// The compiler provides shallow copy
		// m.Age = p.m_Age;
		
		// Should check if there are properties in the heap area, if there are, release them first, and then perform deep copy
		if (m_Age != NULL) {
			delete m_Age;
			m_Age = NULL;
		
 
		// Deep copy
		m_Age = new int(*p.m_Age);
		// Return the object itself
		return *this;
	
	int* m_Age;
};
void test01() {
	Person p1(18);
	Person p2(20);
	Person p3(30);
	p3 = p2 = p1; // Assignment operation
	cout << "p1's age=" << *p1.m_Age << endl;
	cout << "p2's age=" << *p2.m_Age << endl;
	cout << "p3's age=" << *p3.m_Age << endl;

int main() {
	test01();
 
	system("pause");
	return 0;

5. Overload the relational operator

The purpose: Overloading the relational operator allows two custom type objects to perform comparison operations.

#include <iostream>
#include <string>
using namespace std;
 
// Overload the relational operator
 
class Person {
public:
	Person(string name,int age):m_Name(name), m_Age(age){}
	// Overload the == operator
	bool operator==(Person& p) 
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {
			return 1;
		
		else
			return 0;
	
	string m_Name;
	int m_Age;
};
void test01() {
	Person p1("TOM", 18);
	Person p2("Jerry", 18);
	if (p1 == p2) {
		cout << "p1 and p2 are equal" << endl;
	
	else
	{
		cout << "p1 and p2 are not equal" << endl;
	

int main() {
	test01();
	system("pause");
	return 0;

6. Overload the function call operator

1. The function call operator (()) can also be overloaded
2. Since the calling method after overloading is very similar to a function call, it is calledTemplate function
3. The template function has no fixed writing style and is very flexible

#include <iostream>
#include <string>
using namespace std;
 
// Overload the function call operator
 
// Print output class
 
class MyPrint {
public:
	// Overload the function call operator
	void operator()(string test) {
		cout << test << endl;
	
};
void MyPrint02(string test){
	cout << test << endl;

void test01() {
	MyPrint myprint;
 
	myprint("hello word");//Since it is very similar to function calls in use, it is called a template function
 
	MyPrint02("hello word");

// The template function is very flexible and has no fixed writing style
// Add class
 
class Myadd {
public:
	int operator()(int num1,int num2) {
		return num1 + num2;
	
};
void test02() {
	Myadd add;
	int ret=add(100,100);
	cout << "ret=" << ret << endl;
	
	//Anonymous function object
	cout << Myadd()(100, 100) << endl;

int main() {
	test01();
	test02();
	system("pause");
	return 0;

Class and object-inheritance-basic syntax

For example, we can see that many websites have common headers, footers, and even common left lists, with only the central content being different
Next, we will implement the content of the web page using both normal writing and inheritance writing, and see the significance and benefits of inheritance

#include <stdio.h>
#include <iostream>
using namespace std;
 
//Normal implementation page
 
//Java page
class Java {
public:
	void header() {
		cout << "Home page, open courses, login and so on" << endl;
	
	void footer() {
		cout << "Help center, cooperation and so on" << endl;
	
	void left() {
		cout << "Java, Python, C++ and so on" << endl;
	
	void content() {
		cout << "Java learning videos" << endl;
	
};
//Python
class Python {
public:
	void header() {
		cout << "Home page, open courses, login and so on" << endl;
	
	void footer() {
		cout << "Help center, cooperation and so on" << endl;
	
	void left() {
		cout << "Java, Python, C++ and so on" << endl;
	
	void content() {
		cout << "Python learning videos" << endl;
	
};
//C++
class Cpp {
public:
	void header() {
		cout << "Home page, open courses, login and so on" << endl;
	
	void footer() {
		cout << "Help center, cooperation and so on" << endl;
	
	void left() {
		cout << "java, python, c++ and so on" << endl;
	
	void content() {
		cout << "C++ learning videos" << endl;
	
};
 
void test01() {
	cout << "-------------------" << endl;
	cout << "Java video download page is as follows: " << endl;
	Java a;
	a.header();
	a.footer();
	a.left();
	a.content();
 
	cout << "-------------------" << endl;
	cout << "Python video download page is as follows: " << endl;
	Python p;
	p.header();
	p.footer();
	p.left();
	p.content();
 
	cout << "-------------------" << endl;
	cout << "C++ download video page as follows: " << endl;
	Cpp c;
	c.header();
	c.footer();
	c.left();
	c.content();

int main() {
	test01();
	return 0;

After using inheritance:

#include <stdio.h>
#include <iostream>
using namespace std;
 
// Inheritance implementation page
// Benefits of inheritance: reduce redundant code
// Syntax: class child : inheritance_mode parent
// Child class also known as derived class
// Parent class also known as base class
 
//Common implementation page
class BasePage {
	public:
		void header() {
			cout << "Home page, open courses, login and so on" << endl;
		
		void footer() {
			cout << "Help center, cooperation and so on" << endl;
		
		void left() {
			cout << "Java, Python, C++ and so on" << endl;
		
		void content() {
			cout << "Java learning videos" << endl;
		
	};
 
//Java page
class Java :public BasePage {
public:
	void content() {
		cout << "Java subject videos" << endl;
	
};
//Python
class Python :public BasePage {
public:
	void content() {
		cout << "Python subject videos" << endl;
	
};
//Cpp
class Cpp :public BasePage {
public:
	void content() {
		cout << "C++ subject videos" << endl;
	
};
void test01() {
	cout << "-------------------" << endl;
	cout << "Java video download page is as follows: " << endl;
	Java a;
	a.header();
	a.footer();
	a.left();
	a.content();
 
	cout << "-------------------" << endl;
	cout << "Python video download page is as follows: " << endl;
	Python p;
	p.header();
	p.footer();
	p.left();
	p.content();
 
	cout << "-------------------" << endl;
	cout << "C++ download video page as follows: " << endl;
	Python c;
	c.header();
	c.footer();
	c.left();
	c.content();

int main() {
	test01();
	return 0;

Summary:

The benefits of inheritance: it can reduce redundant code
class A: public B;
Class A is called the subclass orderived class
Class B is called the base class or base class
The members in the derived class include two major parts:
One type is inherited from the base class, and the other is the members added by itself.
The inherited members from the base class show their commonality, while the newly added members reflect their individuality.

Class and object - inheritance - inheritance methods

Inheritance syntax:class subclass: inheritance method base class

There are three types of inheritance methods:

1.Public inheritance

2.Protected inheritance

3.Private inheritance

1739773883_67b2d7bb81ccdef0f565f.png!small?1739773884700

#include <stdio.h>
#include <iostream>
using namespace std;
 
// Inheritance methods
// Public inheritance
 
class Base1 {
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};
 
class Son1 :public Base1 {
public:
	void func() {
		int m_A = 10; // Public access permission member of the base class remains public in the subclass
		int m_B = 10; // Protected access permission member of the base class remains protected in the subclass
		// int m_C = 10; // Private access permission member of the base class, not accessible by the subclass
	
};
void test01() {
	Son1 s1;
	s1.m_A = 100;
	// s1.m_B = 100; // m_B is protected in Son1, not accessible from outside

 
// Protected inheritance
class Base2 {
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};
class Son2:protected Base2
{
public:
	void func() {
		m_A = 100; // Public member in the base class remains protected in the subclass
		m_B = 100; // Protected member in the base class remains protected in the subclass
		// m_C = 100; // Private member in the base class, not accessible by the subclass
	
};
void test02() {
	Son2 s1;
	// s1.m_A = 1000; // m_A becomes protected in Son2, not accessible from outside
	// s1.m_B = 1000; // m_B has protected access in Son2, not accessible from outside

// Private inheritance
class Base3 {
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};
class Son3 :private Base3 {
public:
	void func() {
		m_A = 100; // Public member in the base class becomes private in the subclass
		m_B = 100; // Protected member in the base class becomes private in the subclass
		//m_C = 100; // Private member in the base class, not accessible by the subclass
	
};
class GrandSon3 :public Son3 {}
public:
	void func() {
		//m_A = 1000;//It becomes private in Son3, even the grandchild cannot access it
		//m_B = 1000;//It becomes private in Son3, even the grandchild cannot access it
	
};
void test03() {
	Son3 s1;
	//s1.m_A = 1000;//It becomes a private member in Son3, and it is inaccessible from outside the class
	//s1.m_B = 1000;//It becomes a private member in Son3, and it is inaccessible from outside the class

int main() {
	test01();
	return 0;

Class and object - inheritance - object model in inheritance

Question:fromClass inheritancemembers coming from the parent

#include <stdio.h>
#include <iostream>
using namespace std;
 
//The object model in inheritance
 
class Base {
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};
 
class Son :public Base {
public:
	int m_D;
};
 
void test01() {
	//All non-static member variables of the parent class are inherited by the subclass
	//The private member attributes of the parent class are hidden by the compiler, so they are inaccessible, but they are indeed inherited
	cout << "size of Son=" << sizeof(Son) << endl;

 
int main() {
	test01();
	return 0;

Class and object - inheritance - construction and destruct order


Subclass inherits from the parent classAfter that, when creating a subclass object, the parent class'sDestructor

Question: Who calls the construction and destruct order first between the parent class and the subclass?

#include <stdio.h>
#include <iostream>
using namespace std;
 
//The construction and destruct order in inheritance
class Base {
public:
	Base() {
		cout << "Base's constructor" << endl;
	
	~Base() {
		cout << "Base destructor" << endl;
	
};
class Son :public Base {
public:
	Son() {
		cout << "Son's constructor" << endl;
	
	~Son() {
		cout << "Son destructor" << endl;
	
};
 
void test01() {
	//Base b;
 
	//The construction and destruct order in inheritance is as follows:
	//First construct the parent class, then construct the subclass, and the destruct order is the opposite of the construction order
	Son s;

 
int main() {
	test01();
	return 0;

Summary:In inheritance, the parent class is called firstConstructor, and then call the subclass constructor, the destruct order is the opposite of the construction order (first call the subclass destructor and then call the parent class destructor)

Class and object - inheritance - handling of same-name members

Question: When a subclass and its parent class have the same-name members, how to access them through the subclass and object?Class object, how to access the same-name data in the subclass or parent class?

To access the same-name members of the subclass, direct access is sufficient
To access the same-name members of the parent class, a scope resolution operator is needed

#include <stdio.h>
#include <iostream>
using namespace std;
 
//Handling of same-name members in inheritance
class Base {
public:
	Base() {
		m_A = 100;
	
	int m_A;
	void func() {
		cout << "Base under func call" << endl;
	
	void func(int a) {
		cout << "Base under func(int a) call" << endl;
	
};
class Son :public Base {
public:
	Son() {
		m_A = 200;
	
	int m_A;
	void func() {
		cout << "Son\'s func call" << endl;
	
};
//Handling of same name member properties
void test01() {
	Son s;
	cout << "Son\'s m_A=" << s.m_A << endl;
	//If you access the same name member in the parent class through the subclass object, you need to add the scope resolution operator
	cout << "Base\'s m_A=" << s.Base::m_A << endl;

//Handling of same name member functions
void test02() {
	Son s;
	s.func();
	s.Base::func();
	//If there is a member function with the same name as the parent class in the subclass, the subclass same name member will hide all the same name member functions in the parent class
	//If you want to access the hidden same name member function in the parent class, you need to add the scope resolution operator
	s.Base::func(100);

 
int main() {
	test01();
	test02();
	return 0;

Summary:
1. The subclass object can directly access the same name members in the subclass
2. You can access the same name members of the parent class by adding the scope resolution operator to the subclass object
3. When the subclass and the parent class have the same name membersfunction, the subclass will hide the same name member function in the parent class, and you can access the same name function in the parent class by adding the scope resolution operator

Class and object - inheritance - handling of same name static members

Question: Same name in inheritanceStatic membersHow to access it on a subclass object?

The handling method for static members and non-static members with the same name is consistent

To access the same name member of the subclass, you can access it directly
To access the same name member of the parent class, you need to add the scope resolution operator

#include <stdio.h>
#include <iostream>
using namespace std;
 
//Handling of same name static members in inheritance
 
class Base {
public:
	static int m_A;
 
	static void func() {
		cout << "Base\'s static void func function call" << endl;
	
};
int Base::m_A = 100;
class Son:public Base {
public:
	static int m_A;
 
	static void func() {
		cout << "Son\'s static void func function call" << endl;
	
};
int Son::m_A = 200;
 
//Same name static member properties
void test01() {
 
	//1. Accessing through an object
	Son s;
	cout << "m_A=" << s.m_A << endl;
	cout << "m_A=" << s.Base::m_A << endl;
 
	//2. Accessing through class name
	cout << "Accessed through class name" << endl;
	cout << "Son\'s m_A=" << Son::m_A << endl;
	//The first :: represents accessing through the class name, the second :: represents accessing the scope under the parent class
	cout << "Base\'s m_A=" << Son::Base::m_A << endl;

//Handling of same static member functions
void test02() {
	//Accessed through object
	cout << "Accessed through object" << endl;
	Son s;
	s.func();
	s.Base::func();
	
	//Accessed through class name
	cout << "Accessed through class name" << endl;
	Son::func();
	Son::Base::func();

int main() {
	test01();
	test02();
	return 0;

Summary:The handling method of the same static member is the same as that of non-static members, but there are two ways to access them (through objects and through class names)

Class and object - inheritance - inheritance syntax

C++ allows aClass inheritanceMultiple classes

Syntax: class subclass:inheritance mode parent class1, inheritance mode parent class2...

Multiple inheritanceIt may cause duplicate names in the parent class, and scope resolution needs to be added to distinguish

It is not recommended to use multiple inheritance in actual C++ development

#include <stdio.h>
#include <iostream>
using namespace std;
 
//Multiple inheritance syntax
 
class Base1 {
public:
	Base1() {
		m_A = 100;
	
	int m_A;
};
 
class Base2 {
public:
	Base2() {
		m_A = 200;
	
	int m_A;
};
//The subclass needs to inherit Base1 and Base2
//Syntax: class subclass:inheritance mode parent class1, inheritance mode parent class2..
class Son :public Base1, public Base2 {
public:
	Son() 
	{
		m_C = 300;
		m_D = 400;
	};
int m_C;
int m_D;
};
void test01() {
	Son s;
	cout << "sizeof Son=" << sizeof(s) << endl;
	//When there are duplicate members in the parent class, add scope resolution to distinguish
	cout << "Base1 m_A=" << s.Base1::m_A << endl;
	cout << "Base2 m_A=" << s.Base2::m_A << endl;

int main() {
	test01();
	return 0;

Summary:In multiple inheritance, if there are duplicate names in the parent class, the child class needs to add scope resolution when using.

Class and object - inheritance - diamond inheritance problem and solution

Diamond inheritanceConcept:
Twoderived classInheriting the same base class
There is also a class that inherits two derived classes at the same time
This kind of inheritance is called diamond inheritance, or diamond-shaped inheritance

Typical diamond inheritance case:

1739774117_67b2d8a58985db14038c0.png!small?1739774118413

Diamond inheritance problem:
1. The sheep inherits the data of animals, and the camel also inherits the data of animals. When the horse uses the data, ambiguity will arise.
2. The horse inheritance automatically inherits two copies of animal data, but actually we should be clear that we only need one copy of this data.

#include <stdio.h>
#include <iostream>
using namespace std;
 
//Animal class
class Animal {
public:
	int m_A;
};
//Virtual inheritance can be used to solve the diamond inheritance problem 
//Before inheritance, add the keyword 'virtual' to become virtual inheritance
//The Animal class is called a virtual base class
//Sheep class
class Sheep:virtual public Animal{};
//Camel class
class Tuo :virtual public Animal {};
//Alpaca class
class Sheeptuo:public Sheep,public Tuo{};
void test01() {
	Sheeptuo st;
	st.Sheep::m_A = 18;
	st.Tuo::m_A = 28;
	//When diamond inheritance, two parent classes have the same data, it is necessary to distinguish the scope of action.
	cout << "st.Sheep::m_A =" << st.Sheep::m_A << endl;
	cout << "st.Tuo::m_A = " << st.Tuo::m_A << endl;
	cout << "st,m_A=" << st.m_A << endl;
	//We know that this data, just one copy is enough, diamond inheritance leads to two copies of data, wasting resources.
 

int main() {
	test01();
	return 0;

Summary:
The main problem brought about by diamond inheritance is that the subClass inheritanceTwo copies of the same data lead to waste of resources and meaninglessness
Virtual inheritance can be used to solve the diamond inheritance problem

Class and object - polymorphism - basic syntax of polymorphism

Polymorphism is one of the three major features of C++ object-oriented programming
PolymorphismIt is divided into two categories
1. Static polymorphism:Function overloadingand function name overloading belong to static polymorphism, reusing function names
2. Dynamic polymorphism:derived classandVirtual functionImplement runtime polymorphism

Differences between static polymorphism and dynamic polymorphism:
1. Static polymorphism - the function address is bound early at the compilation stage
2. Dynamic polymorphism - the function address is bound late at runtime

The following explains polymorphism through an example:

#include <stdio.h>
#include <iostream>
using namespace std;
 
//Polymorphism
 
//Animal class
class Animal {
public:
	//Virtual function
	virtual void speak() {
		cout << "The animal is speaking" << endl;
	
};
 
//Cat class
class Cat:public Animal{
public:
	//Rewrite the function with the same return value type, function name, and parameter list
	void speak() {
		cout << "The cat is speaking" << endl;
	
};
 
//Dog class
class Dog :public Animal {
public:
	void speak() {
		cout << "The dog is speaking" << endl;
	
};
//Execute the speaking function
//Early binding of the address determines the function address at the compilation stage
//If you want to execute the function to make the cat speak, then this function cannot be bound in advance. It needs to be bound at runtime, and the address is late binding
 
//Dynamic polymorphism meets the conditions
//There is an inheritance relationship
//The subclass needs to override the virtual function of the superclass
 
//Dynamic polymorphism usage
//Pointer or reference of the superclass executes subclass object
 
void dospeak(Animal &animal)//Animal & animal=cat;
{
	animal.speak();

void test01() {
	Cat cat;
	dospeak(cat);
 
	Dog dog;
	dospeak(dog);
 
	Animal animal;
	dospeak(animal);

int main() {
	test01();
	return 0;

Class and object - polymorphism - case 1 - calculator class

Case description:
Implement using both normal writing andPolymorphismTechnology, design and implement twoOperandsCalculator class for performing operations

Advantages of polymorphism:
1. Clear code organization structure
2. High readability
3. Beneficial for early and late expansion and maintenance

#include <stdio.h>
#include <iostream>
#include<string>
using namespace std;
 
//Implement calculator class using both normal writing and polymorphism technology
 
//Normal writing
class Calculator {
public:
	int getResult(string oper) {
		if (oper == "+") {
			return m_Num1 + m_Num2;
		
		else if (oper == "-") {
			return m_Num1 - m_Num2;
		
		else if (oper == "*") {
			return m_Num1 * m_Num2;
		
		//If you want to expand new functions, you need to modify the source code
		//In real development, advocate the Open-Closed Principle
		//Open-Closed Principle: Open for expansion, closed for modification
	
	int m_Num1;
	int m_Num2;
};
 
void test01() {
	//Create calculator object
	Calculator c;
	c.m_Num1 = 10;
	c.m_Num2 = 20;
 
	cout << c.m_Num1 << "+" << c.m_Num2 << "=" << c.getResult("+") << endl;
	cout << c.m_Num1 << "-" << c.m_Num2 << "=" << c.getResult("-") << endl;
	cout << c.m_Num1 << "*" << c.m_Num2 << "=" << c.getResult("*") << endl;

 
 
 
// Utilize polymorphism to implement calculator
 
// Benefits of polymorphism:
// 1. Clear organization structure
// 2. High readability
// 3. Good for early and late expansion and high maintainability
 
//Implement the abstract class of calculator
class AbstractCalculator {
public:
	virtual int getResult() {
		return 0;
	
	int m_Num1;
	int m_Num2;
};
//Addition calculator class
class AddCalculator :public AbstractCalculator {
public:
	int getResult() {
		return m_Num1 + m_Num1;
	
};
//Subtraction calculator class
class SubCalculator :public AbstractCalculator {
public:
	int getResult() {
		return m_Num1 - m_Num1;
	
};
//Multiplication calculator class
class MulCalculator :public AbstractCalculator {
public:
	int getResult() {
		return m_Num1 * m_Num1;
	
};
void test02() {
	//Condition for polymorphism usage
	//Parent class pointer or reference to subclass object
 
	//Addition operation
	AbstractCalculator* abc = new AddCalculator;
	abc->m_Num1 = 100;
	abc->m_Num2 = 100;
 
	cout << abc->m_Num1 << "+" << abc->m_Num2 << "=" << abc->getResult() << endl;
	//Remember to destroy after use
	delete abc;
 
	//Subtraction operation
	abc = new SubCalculator;
	abc->m_Num1 = 100;
	abc->m_Num2 = 100;
 
	cout << abc->m_Num1 << "-" << abc->m_Num2 << "=" << abc->getResult() << endl;
	delete abc;
 
	//Multiplication operation
	abc = new MulCalculator;
	abc->m_Num1 = 100;
	abc->m_Num2 = 100;
 
	cout << abc->m_Num1 << "*" << abc->m_Num2 << "=" << abc->getResult() << endl;
	delete abc;

int main(){
	//test01();
	test02();
	system("Pause");
	return 0;

Summary: C++ development advocates the use of polymorphism to design program architecture, because there are many advantages of polymorphism

Class and object - polymorphism - pure virtual function and abstract class

InPolymorphismIn, the implementation of virtual functions in the parent class is usually meaningless, mainly calling the childClass rewritingcan be

Therefore, the content ofVirtual functionChange toPure virtual function

Syntax of pure virtual function:
virtual Return value type Function name (parameter list) = 0;

When a class has pure virtual functions, this class is also calledAbstract class

Characteristics of abstract classes:
1. Cannot instantiate an object
2. The subclass must override the pure virtual function of the abstract class, otherwise it also belongs to the abstract class

#include <stdio.h>
#include <iostream>
#include<string>
using namespace std;
 
//Pure virtual function and abstract class
class Base
{
public:
	// Pure virtual function
	//If there is a pure virtual function, this class is called an abstract class
	//Characteristics of abstract classes:
	//1. Cannot instantiate an object
	//2. The subclass of an abstract class must = override the pure virtual function of the superclass, otherwise it also belongs to the abstract class
	virtual void func() = 0;
};
class Son :public Base {
public:
	virtual void func() {
		cout << "func function call" << endl;
	
};
void test01() {
	//Base b;//The abstract class cannot instantiate an object
	//new Base;//The abstract class cannot instantiate an object
 
	//Son s;//The subclass must override the pure virtual function of the superclass, otherwise the object cannot be instantiated
	Base* base = new Son;
	base->func();

int main() {
	test01();
	system("pause");
	return 0;

Class and object - polymorphism - case 2 - make drink

Case description:
Make drinkthe general process is: boil water - brew - pour into cup - add ingredients


UsingPolymorphismThis case implements the technology, providing an abstract base class for making drinks, and provides subclasses for makingCoffee and tea

#include <stdio.h>
#include <iostream>
#include<string>
using namespace std;
 
//Case of polymorphism 2 - Make drink
class Abstractdrinking
{
public:
	//Boil water
	virtual void Boil() = 0;
	//Brew
	virtual void Brew() = 0;
	// Pour into the cup
	virtual void Pourincup() = 0;
	// Add ingredients
	virtual void Putsomething() = 0;
 
	//Make drink
	void makedrink() {
		Boil();
		Brew();
		Pourincup();
		Putsomething();
	
};
class coffee :public Abstractdrinking {
	//Boil water
	virtual void Boil() {
		cout << "Boil Nongfu Spring" << endl;
	
	//Brew
	virtual void Brew() {
		cout << "Brew coffee" << endl;
	
	// Pour into the cup
	virtual void Pourincup() {
		cout << "Pour into the cup" << endl;
	
	// Add ingredients
	virtual void Putsomething(){
		cout << "Add sugar and milk" << endl;
	
 
};
class tea:public Abstractdrinking {
	//Boil water
	virtual void Boil() {
		cout << "Boil mineral water" << endl;
	
	//Brew
	virtual void Brew() {
		cout << "Brew tea" << endl;
	
	// Pour into the cup
	virtual void Pourincup() {
		cout << "Pour into the cup" << endl;
	
	// Add ingredients
	virtual void Putsomething() {
		cout << "Add lemon" << endl;
	
 
};
void dowork(Abstractdrinking *abs) // Abstractdrinking *abs = new coffee
{
	abs->makedrink();
	delete abs; // Release

void test01() {
	dowork(new coffee);
	cout << "------------" << endl;
	dowork(new tea);

int main() {
	test01();
	system("pause");
	return 0;

Class and object - polymorphism - virtual destructor and pure virtual destructor

PolymorphismWhen using, if the subclass has properties allocated to the heap, then the parentClass pointerIt cannot call the subclass destructor code when releasing

Solution: Modify the parent classDestructorChange it to virtual destructor or pure virtual destructor

Commonality of virtual destructor and pure virtual destructor:
// Can solve the problem of releasing a subclassClass object
// Both need to have specific function implementations
Difference between virtual destructor and pure virtual destructor:
// If it is a pure virtual destructor, this class becomes an abstract class and cannot instantiate objects

Syntax of virtual destructor:
virtual ~ClassName() {
Syntax of pure virtual destructor:
virtual ~ClassName() = 0;
ClassName:: ~ClassName() {

#include <stdio.h>
#include <iostream>
#include<string>
using namespace std;
 
// Virtual destructor and pure virtual destructor
 
class Animal {
public:
	Animal() {
		cout << "Animal constructor called" << endl;
	
	// Using virtual destructor can solve the problem of not being clean when releasing a subclass object with a superclass pointer
	/*virtual ~animal()*/
	{
		cout << "Animal destructor called" << endl;
	}*/
	// The pure virtual destructor needs to be declared and implemented
	// With the pure virtual destructor, this class also becomes an abstract class and cannot instantiate objects
	virtual ~Animal() = 0;
	// Pure virtual function
	virtual void speak() = 0;
};
Animal:: ~Animal() {
	cout << "Animal pure virtual destructor called" << endl;

class Cat : public Animal {
public:
	Cat(string name) {
		cout << "Cat constructor called" << endl;
		m_Name = new string(name);
	
	virtual void speak() {
		cout << *m_Name<<"The cat is speaking" << endl;
	
	~Cat()
	{
		if (m_Name != NULL) {
			cout <<"Cat destructor function call" << endl;
			delete m_Name;
			m_Name = NULL;
		
	
	string* m_Name;
};
void test01() {
	Animal* animal = new Cat("Tom");
	animal->speak();
	//When the base class pointer is destructed, the destructor function of the subclass will not be called, leading to memory leakage if the subclass has heap area attributes
	delete animal;

int main() {
	test01();
	system("pause");
	return 0;

Summary:
1. Virtual destructor or pure virtual destructor is used to solve the problem of releasing subclass objects through the base class pointer
2. If there is no heap area data in the subclass, it can be written as virtual destructor or pure virtual destructor
3. Have pureVirtual destructorThe class also belongs to the abstract class

Class and object - polymorphism - case 3 - computer group transformation demand analysis

The main components of the computer areCPU(for calculation),video card(for display),memory module(for storage)
Encapsulate each part intoAbstract base classand provide different parts produced by different manufacturers, such as Intel and Lenovo manufacturers
Create a computer class to provide work for the computerfunctionand call the interface of each part to work
Assemble three different computers for work during testing

#include <stdio.h>
#include <iostream>
#include<string>
using namespace std;
 
//Abstract different part classes
//Abstract CPU class
class CPU{
public:
	//Abstract calculation function
	virtual void calculate() = 0;
};
//Abstract video card class
class VideoCard {
public:
	//Abstract display function
	virtual void display() = 0;
};
//Abstract memory module class
class Memory{
public:
	//Abstract storage function
	virtual void storage() = 0;
};
 
//Computer class
class Computer {
public:
	Computer(CPU* cpu, VideoCard* vc, Memory* mem) {
		m_cpu = cpu;
		m_vc = vc;
		m_mem = mem;
	
	//Provide a work function
	void work() {
		//Let the parts work, call the interface
		m_cpu->calculate();
		m_vc->display();
		m_mem->storage();
	
	//Provide a destructor to release three computer components
	~Computer()
	{
		//Release the CPU component
		if (m_cpu != NULL) {
			delete m_cpu;
			m_cpu = NULL;
		
		//Release the video card component
		if (m_vc != NULL) {
			delete m_vc;
			m_vc = NULL;
		
		//Release the memory module component
		if (m_mem != NULL) {
			delete m_mem;
			m_mem= NULL;
		
	
private:
	CPU* m_cpu;//Pointer to the CPU component
	VideoCard* m_vc;//Pointer to the video card component
	Memory* m_mem;//Pointer to the memory module component
};
 
//Specific manufacturer
//Intel manufacturer
class IntelCPU:public CPU {
public:
	virtual void calculate() {
		cout << "Intel's CPU starts calculating" << endl;
	
};
class IntelVideoCard :public VideoCard {
public:
	virtual void display() {
		cout << "Intel's video card starts displaying" << endl;
	
};
class IntelMemory :public Memory {
public:
	virtual void storage() {
		cout << "Intel's memory module starts displaying" << endl;
	
};
 
//Lenovo manufacturer
class LenovoCPU :public CPU {
public:
	virtual void calculate() {
		cout << "Lenovo's CPU starts calculating" << endl;
	
};
class LenovoVideoCard :public VideoCard {
public:
	virtual void display() {
		cout << "Lenovo's video card starts displaying" << endl;
	
};
class LenovoMemory :public Memory {
public:
	virtual void storage() {
		cout << "Lenovo's memory module starts displaying" << endl;
	
};
 
void test01() {
	cout << "The first computer starts working: " << endl;
	//First computer component
	CPU* intelCpu = new IntelCPU;
	VideoCard* intelCard = new IntelVideoCard;
	Memory* intelMen = new IntelMemory;
 
	//Create the first computer
	Computer* computer1 = new Computer(intelCpu, intelCard, intelMen);
	computer1->work();
	delete computer1;
 
	cout << "-----------------" << endl;
	cout << "The second computer starts working: " << endl;
	//Assembly of the second computer
	Computer* computer2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory);
	computer2->work();
	delete computer2;
 
	cout << "-----------------" << endl;
	cout << "The third computer starts working: " << endl;
	//Assembly of the second computer
	Computer* computer3 = new Computer(new LenovoCPU, new IntelVideoCard, new LenovoMemory);
	computer3->work();
	delete computer3;
};
int main() {
	test01();
	system("pause");
	return 0;

C++ file operations-Text files-Write file

Data generated during program execution are temporary data, and they will be released once the program ends
ThroughFiles can persist data
In C++ forFile operationsIt is necessary to include the header file <fstream

File typesThey are divided into two types:
1.Text files- Files are stored on the computer in ASCII code form as text
2.Binary files- Files are stored in binary form on the computer as text, and users generally cannot read them directly

The three major types of file operations:
1. ofstream: Write operations
2. ifstream: Read operations
3. fstream: Read and write operations

Writing a file:
The steps for writing a file are as follows:
1. Include header file
#include <fstream>
2. Create stream object
ofstream ofs;
3. Open file
ofs.open("File path", opening mode);
4. Write data
ofs << "The data to be written";
5. Close the file
ofs.close();

1739774385_67b2d9b14b5b188eb50c0.png!small?1739774385761

#include <iostream>
#include<fstream>//Include the header file
using namespace std;
 
//Text file Write file
void test01() {
	//1. Include the header file fstream
	//2. Create stream object
	ofstream ofs;
 
	//3. Specify the opening mode
	ofs.open("test.text", ios::out);
 
	//4. Write content
	ofs << "Name: Zhang San" << endl;
	ofs << "Gender: Male" << endl;
	ofs << "Age: 18" << endl;
	//5. Close the file
	ofs.close();

int main() {
	test01();
	system("pause");
	return 0;

Summary:
1. File operation must include the header file fstream
2. Read file can use ofstream, or fstream class
3. When opening the file, you need to specify the path of the file to be operated and the opening mode
4. Use << to write data to the file
5. Close the file after the operation is completed

C++ file operation - text file - read file

Read fileSimilar to write file steps, but there are more read methods

Read file steps are as follows:
1. Include header file
#include <fstream>
2. Create stream object
ifstream ifs;
3. Open file and check if the file is opened successfully
ifs.open("File path", opening mode);
4. Read data
Four ways to read
5. Close the file
ifs.close();

#include <iostream>
using namespace std;
#include<fstream>
#include<string>
 
//Text file read file
void test01() {
	//1. Include header file
 
	//2. Create stream object
	ifstream ifs;
	//3. Open file and check if it is opened successfully
	ifs.open("test.txt",ios::in);
	if (!ifs.is_open()) {
		cout << "File open failed" << endl;
		return;
	
	//4. Read data
 
	//First type
	/*char buf[1024] = { 0 };
	while (ifs >> buf){
		cout << buf << endl;
		}*/
 
	//Second type
	/*char buf[1024] = { 0 };
	while (ifs.getline(buf, sizeof(buf))) {
		cout << buf << endl;
	}*/
 
	//Third type
	/*string buf;
	while (getline(ifs, buf)) {
		cout << buf << endl;
	}*/
 
	//Fourth type
	char c;
	while ((c = ifs.get()) != EOF)//EOF end of file
	{
		cout << c;
	
 
	//5. Close the file
	ifs.close();

 
int main() {
	test01();
	return 0;

Summary:
1. Read file can use ifstream, or fstream class

2. Use is_openfunctionYou can determine whether the file is opened successfully

3. Close the file

C++ file operation - binary file - write file

Read and write file in binary mode
The opening mode needs to be specified as jos:binary

Write file
The binary file write mainly utilizes the member call of the stream objectfunctionwrite
Function prototype:
ostream& write(constchar * buffer, int len);
Parameter explanation: The character pointer buffer points to a segment of memory space. len is the number of bytes to read and write

#include <iostream>
using namespace std;
#include<fstream>
 
//Binary file write file
class Person {
public:
	char m_Name[64]; //Name
	int m_Age; //Age 
};
 
void test01() {
	//1. Include header file
 
	//2. Create stream file
	ofstream ofs("Person.text", ios::out | ios::binary);
	//3. Open file
	//ofs.open("Person.text", ios:: out | ios::binary);
	//4. Write file
	Person P = { "Zhang San", 18 };
	ofs.write((const char*)&P, sizeof(Person));
	//5. Close the file
	ofs.close();

int main() {
	test01();
	return 0;

Read file
Binary modeRead fileMainly uses the stream object to call the member function read
Function prototype:
istream& read(char *buffer, int len);
Parameter explanation: The character pointer buffer points to a segment of memory space. len is the number of bytes to read and write

#include <iostream>
using namespace std;
#include<fstream>
 
class Person {
public:
	char m_Name[64]; //Name
	int m_Age; //Age
};
 
//Read binary file
void test01() {
 
	//1. Include header file
 
	//2. Create stream object
	ifstream ifs;
	//3. Open file and check if the file is opened successfully
	ifs.open("person.text", ios::in | ios::binary);
	if (!ifs.is_open()) {
		cout << "File open failed" << endl;
		return;
	
	//4. Read file
	Person p;
	ifs.read((char*)&p, sizeof(Person));
	cout << "Name: " << p.m_Name << "Age: " << p.m_Age << endl;
	//5. Close the file
	ifs.close();

int main() {
	test01();
	return 0;
你可能想看:

Distributed Storage Technology (Part 2): Analysis of the architecture, principles, characteristics, and advantages and disadvantages of wide-column storage and full-text search engines

Article 2 of the Cryptography Law clearly defines the term 'cryptography', which does not include commonly known terms such as 'bank card password', 'login password', as well as facial recognition, fi

d) Adopt identification technologies such as passwords, password technologies, biometric technologies, and combinations of two or more to identify users, and at least one identification technology sho

4.3. List API: Display all objects (object) that a user can access

4.5 Main person in charge reviews the simulation results, sorts out the separated simulation issues, and allows the red and blue teams to improve as soon as possible. The main issues are as follows

b) It should have the login failure handling function, and should configure and enable measures such as ending the session, limiting the number of illegal logins, and automatically exiting when the lo

b) It should have a login failure handling function, and should configure and enable measures such as ending the session, limiting the number of illegal login attempts, and automatically logging out w

Announcement regarding the addition of 7 units as technical support units for the Ministry of Industry and Information Technology's mobile Internet APP product security vulnerability database

It is possible to perform credible verification on the system boot program, system program, important configuration parameters, and application programs of computing devices based on a credible root,

5. Collect exercise results The main person in charge reviews the exercise results, sorts out the separated exercise issues, and allows the red and blue sides to improve as soon as possible. The main

最后修改时间:
admin
上一篇 2025年03月27日 21:56
下一篇 2025年03月27日 22:19

评论已关闭