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

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:
#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:
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();
#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;

评论已关闭