"C++ Object-Oriented Programming"✍Thousands of details, 40-character summary (recommended collection) "recommended collection"

Hello everyone, meet again, I'm your friend Quanzhanjun.

"C++ object-oriented programming design >✍Thousands of details, 10,000-word summary

Article directory

1. Object-Oriented Programming

Object-Oriented Programming (OOP) is a new programming paradigm. Programming paradigms refer to the specifications, models and styles of designing programs, which are the basis of a class of programming languages.

The procedure-oriented programming paradigm is a widely used procedure-oriented language, and its main features are: a program consists of procedure definitions and procedure calls (simply put, a procedure is a piece of code for a program to perform an operation, and a function is the most commonly used process).

The basic element of an object-oriented program is an object. The main structural characteristics of an object-oriented program are: first, the program generally consists of two parts: the definition of the class and the use of the class; second, all operations in the program are sent by sending messages to the object. To achieve this, after the object receives the message, it starts the relevant method to complete the corresponding operation.

Object: A unity that encapsulates data describing its properties and a set of operations performed on that data. Objects can be thought of as data + operations.

Class: A class is a collection of a group of objects with the same data and the same operations.

Messaging: Interaction between objects.

**Methods:** The behavior that an object implements is called a method.

The basic characteristics of object-oriented programming: abstraction, encapsulation, inheritance, polymorphism.

2. Basic C++

~

2.1 The origin and characteristics of C++

C++ is a combination of process-oriented and object-oriented developed in 1980 by Dr. Bjarne Stroustrup of Bell Labs in the United States, based on the C language, to make up for some defects in the C language and to increase the object-oriented features. programming language. Initially he called the new language "C with classes", until 1983 it was named C++.

Compared with the C language, the main feature of C++ is to increase the object-oriented mechanism.

~

2.2 A simple C++ example program

For detailed creation steps, please refer to the blog [Visual Studio] Create a C/C++ project

#include <iostream> //Compile preprocessing command
using namespace std;    //use namespace

int add(int a, int b);       //Function prototype description

int main()  //main function
{ 
   
	int x, y;
	cout << "Enter two numbers: " << endl;
	cin >> x;
	cin >> y;
	int sum = add(x, y);
	cout << "The sum is : " << sum << '\n';
	return 0;
}

int add(int a, int b) //Define the add() function, the function value is an integer
{ 
   
	return a + b;
}
copy

~

2.3 The extension of C++ to C language in non-object-oriented aspects

input and output
int i;
float f;
cin >> i;
cout << f;
------------
scanf("%d", &i);
printf("%f", f);
----------------
continuous reading
cin >> a >> b >> c;
copy
cin
  • By default, the operator'>'skips the empty White character and reads in the value that follows the variable type. So, spaces, carriage returns, and tabs can be used to separate the input data when entering values for a group of variables.
  • When a string is entered (that is, a variable whose type is string), the purpose of the extract operator'>'is to skip the empty White character, read in the subsequent non-empty White character until another empty White character is encountered, and Put an end-of-string marker'\0' at the end of the string.

~

C++ allows local variables to be declared anywhere in a code block.

const modifier

In the C language, it is customary to use #define to define constants, such as #define PI 3.14, C++ provides a more flexible and safer way to define constants, that is, use the const modifier to define constants. For example const float PI = 3.14;

const can be used with pointers, and their combination is complex and can be classified into three types: pointers to constants, constant pointers, and constant pointers to constants.

illustrate:

  1. If using const to define an integer constant, the keyword can be omitted. That is, const in bufsize = 100 is equivalent to const bufsize = 100;
  2. Once a constant is established, it cannot be changed anywhere in the program.
  3. Unlike #define, const-defined constants can have their own data types.
  4. Function parameters can also be specified with const, which is used to ensure that the actual parameters are not changed within the function.
void pointer

void usually means no value, but when void is used as the type of a pointer, it means an indeterminate type. This void type pointer is a general-purpose pointer, which means that any type of pointer value can be assigned to a void type pointer variable.

It should be pointed out that the void type pointer is a general-purpose pointer, which means that it can accept the assignment of any type of pointer, but for the void type pointer that has been valued, it is reprocessed, such as when outputting or passing the pointer value, Then an explicit type conversion must be performed again, otherwise an error will occur.

    void* pc;
    int i = 123;
    char c = 'a';
    pc = &i;
	cout << pc << endl;         //Output pointer address 006FF730
	cout << *(int*)pc << endl;  //output value 123
    pc = &c;
	cout << *(char*)pc << endl; //output value a
copy
inline function

Prefix the keyword inline to the function name, the function is declared as an inline function. Whenever a call to the function occurs in the program, the C++ compiler uses the code in the function body to insert the statement that calls the function, and uses actual parameters instead of formal parameters, so that no function calls are made when the program is running. The main purpose of introducing inline functions is to eliminate the system overhead when calling functions to improve the running speed.

illustrate:

  • Inline functions must be fully defined before they are called for the first time, otherwise the compiler will not know what code to insert
  • Inline functions generally cannot contain complex control statements, such as for statements and switch statements, etc.
  • The use of inline functions is a measure to exchange space for time. If the inline functions are long, complex and frequently called, it is not recommended to use them.
#include <iostream>
using namespace std;

inline double circle(double r)  //inline function
{ 
   
	double PI = 3.14;
	return PI * r * r;
}

int main() 
{ 
   
	for (int i = 1; i <= 3; i++)
		cout << "r = " << i << " area = " << circle(i) << endl;
	return 0;
}
copy

Use inline functions instead of macro definitions to eliminate the insecurity of macro definitions

function with default parameter values

When a function call is made, the compiler combines the arguments with the formal parameters in left-to-right order. If not enough arguments are specified, the compiler fills in the missing arguments with the default values ​​in the function prototype in order.

void init(int x = 5, int y = 10);
init (100, 19);   // 100 , 19
init(25);         // 25, 10
init();           // 5, 10
copy
function overloading

In C++, users can overload functions. This means that within the same scope, two or more functions can use the same function name as long as the types of function parameters are different, or the number of parameters is different, or both.

#include <iostream>
using namespace std;

int add(int x, int y)
{ 
   
	return x + y;
}

double add(double x, double y)
{ 
   
	return x + y;
}

int add(int x, int y, int z)
{ 
   
	return x + y + z;
}

int main() 
{ 
   
	int a = 3, b = 5, c = 7;
	double x = 10.334, y = 8.9003;
	cout << add(a, b) << endl;
	cout << add(x, y) << endl;
	cout << add(a, b, c) << endl;
	return 0;
}
copy

illustrate:

scope identifier "::"

Normally, if there are two variables with the same name, one is global and the other is local, then the local variable has higher priority in its scope and it will mask the global variable.

If you want to use a global variable with the same name in the scope of a local variable, you can add "::" before the variable, at this time ::value represents the value of the global variable, and "::" is called the scope identifier.

#include <iostream>
using namespace std;

int value;   //Define the global variable value

int main() 
{ 
   
	int value;  //Define the local variable value
	value = 100;
	::value = 1000;
	cout << "local value : " << value << endl;
	cout << "global value : " << ::value << endl;
	return 0;
}
copy
coercion

Different types of data can be converted using casts. For example, to convert an integer (int) to a double (double), use the following format:

int i = 10;
double x = (double)i;
or
int i = 10;
double x = double(i);
copy

Both of the above methods are acceptable to C++, and the latter method is recommended.

new and delete operators

When the program is running, the computer's memory is divided into 4 areas: the program code area, the global data area, the heap and the stack. Among them, the heap can be allocated and freed by the user. The functions malloc() and free() are used in C language for dynamic memory management. C++ provides operators new and delete to do the same job, and the latter has better performance than the former and is more flexible and convenient to use.

pointer variable name = new type
    int *p;
    p = new int;
delete pointer variable name
    delete p;
copy

Here are a few more explanations for the use of new and delete:

quote

References are an important extension of C++ to C. A reference to a variable is an alias for the variable, so the reference is also called an alias.

type &reference name = defined variable name
copy

The reference shares the same memory unit with the variable it represents, and the system does not allocate additional storage space for the reference. In effect, the compilation system makes the reference and the variable it represents have the same address.

#include <iostream>
using namespace std;
int main() 
{ 
   
	int i = 10;
	int &j = i;
	cout << "i = " << i << " j = " << j << endl;
	cout << "i 's address is " << &i << endl;
	cout << "j 's address is " << &j << endl;
	return 0;
}
copy

The above code outputs the same value of i and j, and the same address.

  • A reference is not a separate data type, it must be associated with a variable of a certain type. When declaring a reference, it must be initialized immediately, and cannot be assigned after the declaration is complete.
  • The initial value provided for the reference, which can be a variable or another reference.
  • A pointer accesses a variable indirectly through an address, while a reference accesses a variable directly through an alias.

Using references as function parameters, using references to return function values

#include <iostream>
using namespace std;

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

int a[] = { 
   1, 3, 5, 7, 9};

int& index(int i)
{ 
   
	return a[i];
}

int main() 
{ 
   
	int a = 5, b = 10;
	//Swap numbers a and b
	swap(a, b);
	cout << "a = " << a << " b = " << b << endl;
	cout << index(2) << endl;   //Equivalent to the value of the output element a[2]
	index(2) = 100;             //Equivalent to assigning the value of a[2] to 100;
	cout << index(2) << endl;
	
	return 0;
}
copy

Further clarification of citations

  • Creating a reference of type void is not allowed
  • Cannot create an array of references
  • A reference to a reference cannot be created. A pointer to a reference cannot be created. A reference itself is not a data type, so there are no references to references, and no pointers to references.
  • The address of the reference can be assigned to a pointer, and the pointer points to the original variable.
  • A reference can be qualified with const, which does not allow the value of the reference to be changed, but it does not prevent the value of the variable represented by the reference.

3. Classes and Objects (1)

~

3.1 Composition of classes

The contents of a class declaration include data and functions, called data members and member functions, respectively. According to the access rights, data members and member functions can be divided into three types: public, protected and private.

class class name{ 
   
    public :
        public data members;
        public member functions;
    protected:
        protect data members;
        protect member functions;
    private:
        private data members;
        private member function;
};
copy

such as grades

class Score{ 
   
    public:
    void setScore(int m, int f);
    void showScore();
    private:
    int mid_exam;
    int fin_exam;
};
copy
  • For a specific class, it is not necessary to have all the three parts in the class declaration format, but at least one of them is required. In general, data members of a class should be declared as private members and member functions as public members. In this way, the internal data is completely hidden in the class, and cannot be seen outside the class at all, so that the data can be effectively protected, and it will not affect the rest of the class, and the interaction between programs is reduced. to the minimum.
  • The keywords private, protected, and public in a class declaration can appear in any order.
  • If the private part is in the first part of the class, the keyword private can be omitted. In this way, if a class body does not have an access permission keyword, its data members and member functions are private by default.
  • You cannot assign initial values ​​to data members in a class declaration.

~

3.2 Definition of member functions

Definition of ordinary member functions

Only the prototype of the member function is given in the class declaration, and the definition of the member function is written outside the class. The general form of such a member function defined outside a class is:

return value type class name::member function name(Parameters Table){ 
       function body}
copy

For example, the class Score representing scores can be declared as follows:

class Score{ 
   
public:
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

void Score::setScore(int m, int f) 
{ 
   
	mid_exam = m;
	fin_exam = f;
}

void Score::showScore()
{ 
   
	cout << "midterm grades: " << mid_exam << endl;
	cout << "Final grade:" << fin_exam << endl;
}
copy

Definition of inline member functions

  • Implicit declaration: define member functions directly inside the class
class Score{ 
   
public:
	void setScore(int m, int f)
	{ 
   
		mid_exam = m;
		fin_exam = f;
	}
	void showScore()
	{ 
   
		cout << "midterm grades: " << mid_exam << endl;
		cout << "Final grade:" << fin_exam << endl;
	}
private:
	int mid_exam;
	int fin_exam;
};
copy
  • Explicit declaration: Only the prototype of the member function is given in the class declaration, and the definition of the member function is placed outside the class.
class Score{ 
   
public:
	inline void setScore(int m, int f);
	inline void showScore();
private:
	int mid_exam;
	int fin_exam;
};

inline void Score::setScore(int m, int f) 
{ 
   
	mid_exam = m;
	fin_exam = f;
}

inline void Score::showScore()
{ 
   
	cout << "midterm grades: " << mid_exam << endl;
	cout << "Final grade:" << fin_exam << endl;
}
copy

Note: In a class, when using inline to define an inline function, both the class declaration and the definition of inline member functions must be placed in the same file (or the same header file), otherwise code replacement cannot be performed at compile time.

~

3.3 Definition and use of objects

A collection of things with common properties and behaviors is usually called a class.

An object of a class can be seen as an instance of the class type, and defining an object is similar to defining a general variable.

object definition

  • Declare the object directly while declaring the class
class Score{ 
   
public:
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
}op1, op2;
copy
  • After declaring the class, define the object when using it
  Score op1, op2;
copy

Access to members in an object

object name.data member name object name.member function name[(Parameters Table)]op1.setScore(89, 99);
op1.showScore();
copy

illustrate:

Class Scope and Access Attributes of Class Members

Private members can only be accessed by member functions in the class, and cannot be accessed outside the class through objects of the class.

Generally speaking, public members are the external interface of the class, while private members are the internal data and internal implementation of the class, and do not want to be accessed by the outside world. Dividing the members of a class into different access levels has two advantages: one is information concealment, that is, implementation encapsulation, which separates the internal data of the class from the internal implementation and external interface, so that the external program of the class does not need to know the details of the class. The second is data protection, that is, to protect the important information of the class to prevent other programs from making inappropriate modifications.

object assignment statement

	Score op1, op2;
	op1.setScore(99, 100);
	op2 = op1;
	op2.showScore();
copy

~

3.4 Constructors and Destructors

Constructor

Constructor is a special member function, which is mainly used to allocate space for objects and initialize them. The name of the constructor must be the same as the class name and cannot be arbitrarily named by the user. It can have parameters of any type, but cannot have a return value. It does not need to be called by the user, but is executed automatically when the object is created.

class Score{ 
   
public:
	Score(int m, int f);  //Constructor
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f)
{ 
   
	mid_exam = m;
	fin_exam = f;
}
copy

When creating an object, use the constructor to assign values ​​to data members, usually in the following two forms

illustrate:

  • The name of the constructor must be the same as the class name, otherwise the compiler will treat it as a normal member function.
  • Constructors have no return value, and when defining a constructor, its type cannot be specified.
  • Like ordinary member functions, the function body of the constructor can be written inside the class body or outside the class body.
  • The constructor is generally declared as a public member, but it does not need and cannot be called explicitly like other member functions. It is called automatically when the object is defined, and it is executed only once.
  • Constructors can take no parameters.
member initialization list

When declaring a class, the initialization of data members is generally performed in the constructor with assignment statements. In addition, the initialization of data members can be implemented using a member initialization list.

class name::constructor name([Parameters Table])[:(member initialization list)]
{ 
   
    //Constructor body
}
copy
class A{ 
   
private:
	int x;
	int& rx;
	const double pi;
public:
	A(int v) : x(v), rx(x), pi(3.14)    //member initialization list
	{ 
   	}
	void print()
	{ 
   
		cout << "x = " << x << " rx = " << rx << " pi = " << pi << endl;
	}
};
copy

**Note:** Class members are initialized in the order in which they are declared in the class, regardless of the order in which they are listed in the member initialization list.

Constructor with default parameters
#include <iostream>
using namespace std;

class Score{ 
   
public:
	Score(int m = 0, int f = 0);    //Constructor with default parameters
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f) : mid_exam(m), fin_exam(f)
{ 
   
	cout << "Constructor in use..." << endl;
}

void Score::setScore(int m, int f) 
{ 
   
	mid_exam = m;
	fin_exam = f;
}

void Score::showScore()
{ 
   
	cout << "midterm grades: " << mid_exam << endl;
	cout << "Final grade:" << fin_exam << endl;
}

int main() 
{ 
   
	Score op1(99, 100);
	Score op2(88);
	Score op3;
	op1.showScore();
	op2.showScore();
	op3.showScore();

	return 0;
}
copy
destructor

Destructors are also a special kind of member function. It performs the opposite of the constructor and is usually used for some cleanup tasks when the object is undone, such as freeing the memory space allocated to the object, etc. Destructors have the following characteristics:

  1. A destructor has the same name as a constructor, but it must be preceded by a tilde (~).
  2. Destructors have no parameters and return value, nor can they be overloaded, so there is only one.
  3. The destructor is automatically called by the compilation system when the object is destroyed.
class Score{ 
   
public:
	Score(int m = 0, int f = 0);
	~Score();       //destructor
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f) : mid_exam(m), fin_exam(f)
{ 
   
	cout << "Constructor in use..." << endl;
}

Score::~Score()
{ 
   
	cout << "Destructor in use..." << endl;
}
copy

**Note:** In the following cases, the destructor is automatically called when the object's lifetime ends:

  • If a global object is defined, the destructor of the global object is called when program flow leaves its scope.
  • If an object is defined in a function body, when the function is called, the object should be freed and the destructor will be called automatically.
  • If an object is created using the new operator, delete will automatically call the destructor when it is released using the delete operator.

The following example:

#include <iostream>
#include <string>

using namespace std;

class Student{ 
   
private:
	char *name;
	char *stu_no;
	float score;
public:
	Student(char *name1, char *stu_no1, float score1);
	~Student();
	void modify(float score1);
	void show();
};

Student::Student(char *name1, char *stu_no1, float score1)
{ 
   
	name = new char[strlen(name1) + 1];
	strcpy(name, name1);
	stu_no = new char[strlen(stu_no1) + 1];
	strcpy(stu_no, stu_no1);
	score = score1;
}

Student::~Student() 
{ 
   
	delete []name;
	delete []stu_no;
}

void Student::modify(float score1) 
{ 
   
	score = score1;
}

void Student::show()
{ 
   
	cout << "Name: " << name << endl;
	cout << "student ID: " << stu_no << endl;
	cout << "score:" << score << endl;
}

int main()
{ 
   
	Student stu("Snow Maiden", "2020199012", 99);
	stu.modify(100);
	stu.show();

	return 0;
}
copy
Default constructor and destructor

If no constructor is defined for the class, the compilation system automatically generates a default constructor.

illustrate:

Every class must have a destructor. If no destructor is explicitly defined for a class, the build system automatically generates a default destructor.

Constructor overloading
class Score{ 
   
public:
	Score(int m, int f);  //Constructor
	Score();
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};
copy

**Note:** In a class, ambiguity may arise when a parameterless constructor and a constructor with default parameters are overloaded.

copy constructor

A copy constructor is a special kind of constructor whose formal parameter is a reference to an object of this class. The role of the copy constructor is to use an existing object to initialize the new object when creating a new object.

The copy constructor has the following characteristics:

  • Because the copy constructor is also a constructor, its function name is the same as the class name, and the function does not return a value.
  • The copy constructor has only one parameter and is a reference to an object of the same type.
  • Every class must have a copy constructor. You can define your own copy constructor to initialize new objects as needed; if no copy constructor is defined for the class, the system will automatically generate a default copy constructor for copying out a new object with the exact same value as the data member.

Custom copy constructor

class name::class name(const class name &object name) 
{ 
   
    The function body of the copy constructor;
}

class Score{ 
   
public:
	Score(int m, int f);  //Constructor
	Score();
	Score(const Score &p);  //copy constructor
	~Score();               //destructor
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f)
{ 
   
	mid_exam = m;
	fin_exam = f;
}

Score::Score(const Score &p)
{ 
   
	mid_exam = p.mid_exam;
	fin_exam = p.fin_exam;
}

The general form of calling a copy constructor is:
    class name object 2(Object 1);
    class name object 2 = Object 1;
Score sc1(98, 87);
Score sc2(sc1);    //call copy constructor
Score sc3 = sc2;   //call copy constructor
copy

There are three situations in which the copy constructor is called:

  • When an object of a class is used to initialize another object of that class;
  • When the formal parameter of the function is an object of the class, and the function is called to combine the formal parameter and the actual parameter;
  • When the return value of the function is an object, when the function execution completes and returns to the caller.
Shallow and deep copies

Shallow copy is to assign values ​​one by one to the data members implemented by the default copy constructor. Usually the default copy constructor is able to do the job, but if the class contains pointer-type data, this method of assigning data members one by one will generate an error.

class Student{ 
   
public:
    Student(char *name1, float score1);
    ~Student();
private:
    char *name;
    float score;
};

The following statement will generate an error
Student stu1("White", 89);
Student stu2 = stu1;
copy

The above error is because the memory space pointed to by stu1 and stu2 is the same. After the destructor releases the memory pointed to by stu1, an error will occur when the memory pointed to by stu2 is released, because this memory space has been released. The solution is to redefine the copy constructor to regenerate memory space for its variables.

Student::Student(const Student& stu)
{ 
   
    name = new char[strlen(stu.name) + 1];
    if (name != 0) { 
   
        strcpy(name, stu.name);
        score = stu.score;
    }
}
copy

4. Classes and Objects (2)

~

4.1 Self-referential pointer this

The this pointer holds the address of the current object and is called a self-referencing pointer.

void Sample::copy(Sample& xy)
{ 
   
    if (this == &xy) return;
    *this = xy;
}
copy

~

4.2 Object arrays and object pointers

array of objects

class name array name[subscript expression]
Assigning a value to an array of objects using a constructor with only one parameter
Exam ob[4] = { 
   89, 97, 79, 88};
Assign values ​​to arrays of objects using constructors with no arguments and with one argument
Exam ob[4] = { 
   89, 90};
Assigning a value to an array of objects with a constructor with multiple arguments
Score rec[3] = { 
   Score(33, 99), Score(87, 78), Score(99, 100)};
copy

object pointer

Each object occupies a certain amount of space in memory after initialization. Therefore, an object can be accessed either by its name or by its address. An object pointer is a variable used to store the address of an object. One half of the syntax for declaring an object pointer is: class name * object pointer name

Score score;
Score *p;
p = &score;
p->member function();
copy

Access an array of objects with an object pointer

Score score[2];
score[0].setScore(90, 99);
score[1].setScore(67, 89);

Score *p;
p = score;   //Assign the address of the object score to p
p->showScore();
p++;    //object pointer variable plus 1
p->showSccore();

Score *q;
q =&score[1];   //Assign the address of the second array element to the object pointer variable q
copy

~

4.3 string class

C++ supports two types of strings. The first one is introduced in the C language, including a character array with a terminator '\0' (that is, terminated by NULL). The standard library function provides a set of operations on it. function that can perform many common string operations.

A more convenient string type is declared in the C++ standard library, namely the string class string, which provides the operations required to process strings. To use the string class, you must include the header file string at the beginning of the program, that is, the following statement: #include <string>

Commonly used string class operators are as follows:

=,+,+=,==,!=,<,<=,>,>=,[](access subscript corresponding character),>>(enter),<<(output)
copy
#include <iostream>
#include <string>
using namespace std;

int main()
{ 
   
	string str1 = "ABC";
	string str2("dfdf");
	string str3 = str1 + str2;
	cout<< "str1 = " << str1 << " str2 = " << str2 << " str3 = " << str3 << endl;
	str2 += str2;
	str3 += "aff";
	cout << "str2 = " << str2 << " str3 = " << str3 << endl;
	cout << "str1[1] = " << str1[1] << " str1 == str2 ? " << (str1 == str2) << endl;
	string str = "ABC";
	cout << "str == str1 ? " << (str == str1) << endl;
	return 0;
}
copy

~

4.4 Passing objects to functions

  • Using objects as function parameters: Objects can be passed as parameters to functions in the same way as other types of data. When passing an object to a function, it is passed to the function through the "call by value" method. Therefore, any modification to the object in the function does not affect the object (the arguments themselves) that calls the function.
  • Use the object pointer as a function parameter: the object pointer can be used as a function parameter, and the object pointer can be used as a function parameter to implement pass-by-value call, that is, when the function is called, the actual parameter object and the formal parameter object pointer variable point to the same memory address. During the process, the change of the value of the object pointed to by the formal parameter object pointer also affects the value of the actual parameter object.
  • Using object references as function parameters: In practice, it is very common to use object references as function parameters, and most programmers prefer to use object references instead of object pointers as function parameters. Because using object references as function parameters not only has the advantages of using object pointers as function parameters, but also using object references as function parameters will be simpler and more direct.
#include <iostream>
using namespace std;

class Point{ 
   
public:
	int x;
	int y;
	Point(int x1, int y1) : x(x1), y(y1)  //member initialization list
    { 
    }
	int getDistance() 
	{ 
   
		return x * x + y * y;
	}
};

void changePoint1(Point point)    //Using objects as function parameters
{ 
   
	point.x += 1;
	point.y -= 1;
}

void changePoint2(Point *point)   //Use object pointer as function parameter
{ 
   
	point->x += 1;
	point->y -= 1;
}

void changePoint3(Point &point)  //Using object references as function parameters
{ 
   
	point.x += 1;
	point.y -= 1;
}


int main()
{ 
   
	Point point[3] = { 
   Point(1, 1), Point(2, 2), Point(3, 3)};
	Point *p = point;
	changePoint1(*p);
	cout << "the distance is " << p[0].getDistance() << endl;
	p++;
	changePoint2(p);
	cout << "the distance is " << p->getDistance() << endl;
	changePoint3(point[2]);
	cout << "the distance is " << point[2].getDistance() << endl;

	return 0;
}
copy

~

4.5 Static members

static data member

In a class, if a data member is declared as static, the member is called static data member. Unlike ordinary data members, no matter how many objects of the class are created, there is only one copy of the static data members. In this way, data sharing between different objects of the same class is realized.

The format for defining static data members is as follows: static data type data member name;

illustrate:

static member function

In the class definition, the member function that has a static description in front of it is called a static member function. A static member function belongs to the entire class and is a member function shared by all objects of the class, not an object in the class. The role of static member functions is not to communicate between objects, but to deal with static data members. The format for defining a static member function is as follows:

static return type static member function name (parameter list);

Similar to static data members, the general formats for calling public static member functions are as follows:

class name::static member function name(List of actual parameters);
object.static member function name(List of actual parameters);
object pointer->static member function name(List of actual parameters);
copy

In general, static member functions do not access non-static members of a class. If it is really necessary, static member functions can only access non-static members of the object through the object name (or object pointer, object reference).

Here are a few more explanations for the use of static member functions:

  1. In general, static function members are mainly used to access static member functions. When used with static data members, it achieves the purpose of sharing data between objects in the same class.
  2. Private static member functions cannot be accessed by functions and objects outside the class.
  3. One reason to use a static member function is that it can be used to call a static member function before any object is created, in order to deal with static data members, something that ordinary member functions cannot achieve
  4. The compilation system limits static member functions to internal linkage, that is, functions with the same name in other files linked to the current file will not conflict with this function, maintaining the security of the function's use. This is the use of static member functions. another reason.
  5. Static member functions are part of the class, not the object. If you want to call a public static member function outside the class, it is better to use the following format: class name::static member function name()
#include <iostream>
using namespace std;

class Score{ 
   
private:
	int mid_exam;
	int fin_exam;
	static int count;     //Static data member, used to count the number of students
	static float sum;     //Static data member, used to count cumulative grades at the end of the term
	static float ave;     //Static data member, used to count the final grade point average
public:
	Score(int m, int f);
	~Score();
	static void show_count_sum_ave();   //static member function
};

Score::Score(int m, int f)
{ 
   
	mid_exam = m;
	fin_exam = f;
	++count;
	sum += fin_exam;
	ave = sum / count;
}

Score::~Score()
{ 
   

}

/*** Static member initialization ***/
int Score::count = 0;
float Score::sum = 0.0;
float Score::ave = 0.0;

void Score::show_count_sum_ave()
{ 
   
	cout << "Student number: " << count << endl;
	cout << "Accumulated grades at the end of the term: " << sum << endl;
	cout << "final grade average: " << ave << endl;
}

int main()
{ 
   
	Score sco[3] = { 
   Score(90, 89), Score(78, 99), Score(89, 88)};
	sco[2].show_count_sum_ave();
	Score::show_count_sum_ave();

	return 0;
}
copy

~

4.6 Friends

One of the main features of a class is data hiding and encapsulation, that is, private members (or protected members) of a class can only be used within the scope of the class definition, that is, private members can only be accessed through its member functions. However, sometimes in order to access the private members of the class, it is necessary to call the member function multiple times in the program, which will bring large time and space overhead due to frequent calls, thus reducing the running efficiency of the program. To this end, C++ provides friends to access private or protected members. Friends include friend functions and friend classes.

friend function

A friend function can be either a non-member function that does not belong to any class, or a member function of another class. A friend function is not a member function of the current class, but it can access all members of the class, including private members, protected members, and public members.

When declaring a friend function in a class, you need to add the keyword friend before its function name. This declaration can be placed in the public section, as well as in the protected and private sections. Friend functions can be defined inside the class or outside the class.

1. Declare a non-member function as a friend function

#include <iostream>
using namespace std;
class Score{ 
   
private:
	int mid_exam;
	int fin_exam;
public:
	Score(int m, int f);
	void showScore();
	friend int getScore(Score &ob);
};

Score::Score(int m, int f)
{ 
   
	mid_exam = m;
	fin_exam = f;
}

int getScore(Score &ob)
{ 
   
	return (int)(0.3 * ob.mid_exam + 0.7 * ob.fin_exam);
}

int main()
{ 
   
	Score score(98, 78);
	cout << "grade is: " << getScore(score) << endl;

	return 0;
}
copy

illustrate:

  1. Although friend functions can access private members of class objects, they are not member functions after all. Therefore, when a friend function is defined outside a class, it is not necessary to prefix the function name with "classname::" like member functions.
  2. Because the friend function is not a member of the class, it cannot directly access the data members of the object, nor can it access the data members of the object through the this pointer. It must pass in the object name (or object pointer, object reference) as the entry parameter. Access the data members of this object.
  3. Friend function provides a mechanism for data sharing between member functions of different classes, and between class member functions and general functions. Especially when a function needs to access multiple classes, friend functions are very useful. Ordinary member functions can only access the class to which they belong, but friend functions of multiple classes can access the data of all related classes.

Example: A function is defined as a friend function of two classes at the same time

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

class Score;    //Advance reference to the Score class
class Student{ 
   
private:
	string name;
	int number;
public:
	Student(string na, int nu) { 
   
		name = na;
		number = nu;
	}
	friend void show(Score &sc, Student &st);
};

class Score{ 
   
private:
	int mid_exam;
	int fin_exam;
public:
	Score(int m, int f) { 
   
		mid_exam = m;
		fin_exam = f;
	}
	friend void show(Score &sc, Student &st);
};

void show(Score &sc, Student &st) { 
   
	cout << "Name:" << st.name << " student ID:" << st.number << endl;
	cout << "Midterm grades:" << sc.mid_exam << " Final grade:" << sc.fin_exam << endl;
}

int main() { 
   
	Score sc(89, 99);
	Student st("White", 12467);
	show(sc, st);

	return 0;
}
copy

2. Declare member functions as friend functions

A member function of a class can be used as a friend of another class. It is one of the friend functions, which is called a friend member function. The friend member function can not only access the private members and public members of the class object where it is located, but also access all the members of the class object where the friend declaration statement is located, so that the two classes can cooperate and coordinate with each other to complete a certain task.

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

class Score;    //Advance reference to the Score class
class Student{ 
   
private:
	string name;
	int number;
public:
	Student(string na, int nu) { 
   
		name = na;
		number = nu;
	}
	void show(Score &sc);
};

class Score{ 
   
private:
	int mid_exam;
	int fin_exam;
public:
	Score(int m, int f) { 
   
		mid_exam = m;
		fin_exam = f;
	}
	friend void Student::show(Score &sc);
};

void Student::show(Score &sc) { 
   
	cout << "Name:" << name << " student ID:" << number << endl;
	cout << "Midterm grades:" << sc.mid_exam << " Final grade:" << sc.fin_exam << endl;
}

int main() { 
   
	Score sc(89, 99);
	Student st("White", 12467);
	st.show(sc);

	return 0;
}
copy

illustrate:

  1. When a member function of a class is used as a friend function of another class, the class must be defined first. And when declaring a friend function, you need to add the class name of the class where the member function is located;
friend class

A class can be declared a friend of another class

class Y{ 
   
    ···
};
class X{ 
   
    friend Y;    //Declare class Y as a friend class of class X
};
copy

When a class is declared as a friend class of another class, all its member functions become friend functions of another class, which means that all member functions in the friend class can access the other class. all members of .

Friendship is not commutative and transitive.

~

4.7 Composition of classes

Embedding objects of another class as data members in one class is called composition of classes. This embedded object is called an object member, also known as a child object.

class Y{ 
   
    ···
};
class X{ 
   
    Y y;
    ···
};
copy

~

4.8 Protection of Shared Data

The introduction of the constant type is to protect the data sharing and prevent the data from being changed. The constant type refers to the type specified by the type modifier const, and the value of the variable or object member of the constant type cannot be changed during the operation of the program.

often quoted

If the reference is declared with const, the declared reference is a constant reference. Objects referenced by const references cannot be updated. If a constant reference is used as a formal parameter, no undesired changes to the actual parameter will occur.

const type & reference name

int a = 5;
const int& b = a;
Right now b Assignment is illegal.
---------------------------
int add(const int& m, const int& n) { 
   
    return m + n;
}
variable in this function m and variable n Illegal when updating
copy

constant object

If you use const when declaring an object, the declared object is a constant object. The data members in a constant object are constants and must have an initial value.

classname const objectname[(parameter list)];

const Date date(2021, 5, 31);
copy

constant object member

1. Constant data members

The data members of the class can be constants or constant references, and the data members specified by const are called constant data members. If a constant data member is declared in a class, the constructor can only initialize the data member through the member initialization list, and no other function can assign a value to the member.

class Date{ 
   
private:
	int year;
	int month;
	int day;
public:
	Date(int y, int m, int d) : year(y), month(m), day(d) { 
   

	}
};
copy

Once a constant data member of an object is initialized, the value of the data member cannot be changed.

2. Constant member function

Type function name (parameter list) const;

Const is an integral part of the function type, so the keyword const must be used when declaring and defining functions. There is no need to add const when calling.

class Date{ 
   
private:
	int year;
	int month;
	int day;
public:
	Date(int y, int m, int d) : year(y), month(m), day(d){ 
   

	}
	void showDate();
	void showDate() const;
};

void Date::showDate() { 
   
	//···
}

void Date::showDate() const { 
   
	//···
}
copy

The keyword const can be used to distinguish overloaded functions.

illustrate:

  1. Constant member functions can access constant data members as well as ordinary data members.
  2. A constant object can only call its constant member objects, but cannot call ordinary member functions. A const member function is the only external interface to a const object.
  3. The constant object function cannot update the data member of the object, nor can it call the ordinary member function of the class, which ensures that the value of the data member will never be updated in the constant member function.

V. Inheritance and Derivation

Inheritance can create new classes on the basis of existing classes, new classes can inherit member functions and data members from one or more existing classes, and can redefine or add new data and functions to form a class. level or grade. Among them, the existing class is called the base class or parent class, and the new class established on it is called the derived class or subclass.

~

5.1 The concept of inheritance and derivation

Inheritance of classes is when a new class acquires existing features from an existing class. Looking at this problem from another angle, the process of generating a new class from an existing class is the derivation of a class. The inheritance and derivation mechanism of classes better solve the problem of code reuse.

Regarding the relationship between the base class and the derived class, it can be expressed as: the derived class is the reification of the base class, and the base class is the abstraction of the derived class.

Examples of using inheritance are as follows:

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

class Person{ 
   
private:
	string name;
	string id_number;
	int age;
public:
	Person(string name1, string id_number1, int age1) { 
   
		name = name1;
		id_number = id_number1;
		age = age1;
	}
	~Person() { 
   

	}
	void show() { 
   
		cout << "Name: " << name << " identity number: " << id_number << " age: " << age << endl;
	}
};

class Student:public Person{ 
   
private:
	int credit;
public:
	Student(string name1, string id_number1, int age1, int credit1):Person(name1, id_number1, credit1) { 
   
		credit = credit1;
	}
	~Student() { 
   

	}
	void show() { 
   
		Person::show();
		cout << "credit: " << credit << endl;
	}
};

int main() { 
   
	Student stu("White", "110103**********23", 12, 123);
	stu.show();

	return 0;
}
copy

When a new class is derived from an existing class, the following functions can be performed in the derived class:

  1. New data members and member functions can be added
  2. Members of the base class can be redefined
  3. You can change the access properties of base class members in derived classes
Access properties of base class members in derived classes

A derived class can inherit members of the base class except for the constructor and destructor, but the access properties of these members can be adjusted during the derivation process. Members inherited from the base class also have different access properties in the derived class.

members of the base class

Inheritance

Base class access properties in derived classes

private

public|protected|private

not directly accessible

public

public|protected|private

public|protected|private

protected

public|protected|private

protected|protected|private

Derived class access rules for base class members

The members of the base class can have access attributes in public, protected, and private3, and the member functions of the base class can access other members of the base class, but outside the class through the object of the base class, only the public members of the base class can be accessed. Similarly, the members of a derived class can also have three access attributes: public, protected, and private. The member functions of the derived class can access the members added by themselves in the derived class, but outside the derived class, through the object of the derived class, you can only access the derived class. public members of the class.

There are two main forms of access to base class members from a derived class:

  • Internal access: Access to members inherited from the base class by the newly added member functions in the derived class.
  • Object Access: Outside the derived class, access to members inherited from the base class through objects of the derived class.

~

5.2 Constructors and Destructors of Derived Classes

The main function of the constructor is to initialize the data. In a derived class, if you initialize the new members of the derived class, you need to add the constructor of the derived class. At the same time, the initialization of all members inherited from the base class is still done by the constructor of the base class, but the constructor and destructor of the base class cannot be inherited, so it must be done in the constructor of the derived class. The parameters required by the constructor of the base class are set. In the same way, the finishing and cleaning of the object of the deriving class also needs to be completed by adding a new destructor.

call sequence

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

class A{ 
   
public:
	A() { 
   
		cout << "A class object construction..." << endl;
	}
	~A() { 
   
		cout << "destruct A class object..." << endl;
	}
};

class B : public A{ 
   
public:
	B() { 
   
		cout << "B class object construction..." << endl;
	}
	~B(){ 
   
		cout << "destruct B class object..." << endl;
	}
};

int main() { 
   
	B b;
	return 0;
}
copy

The result of running the code is as follows:

A class object construction...
B class object construction...
destruct B class object...
destruct A class object...
copy

It can be seen that the invocation of the constructor is strictly in accordance with the order in which the constructor of the base class is called first, and then the constructor of the derived class is called. Destructors are called in the opposite order to constructors, with the destructor of the derived class being called first, and then the destructor of the base class being called.

Construction Rules for Derived Class Constructors and Destructors

The general format of a derived class constructor is:
derived class name(List of parameters):base class name(Parameters Table) { 
   
    Derived class added data member initialization statement
}
-----------------------------------------------------------------
Constructor of a derived class with child objects:
derived class name(List of parameters):base class name(Parameter table 0),child object name 1(Parameter table 1),...,child object name n(Parameters Table n)
{ 
   
    Derived class new member initialization statement
}
copy

When defining a derived class object, the constructors are called in the following order:

Call the constructor of the base class to initialize the data members of the base class.

Call the child object's constructor to initialize the child object's data members.

Call the constructor body of the derived class to initialize the data members of the derived class.

illustrate:

  1. When the base class constructor takes no parameters, the derived class does not necessarily need to define a constructor; however, when the base class constructor has only one parameter, all its derived classes must define a constructor, even the defined derived class The function body of the constructor may be empty, it only plays the role of parameter passing.
  2. If the base class uses a default constructor or a constructor without parameters, the ": base class constructor name (parameter list)" can be omitted when defining the constructor in the derived class. At this time, the derived class does not need a constructor. , you can not define a constructor.
  3. If the base class of the derived class is also a derived class, each derived class only needs to be responsible for the initialization of the data members of its direct base class, and trace back in turn.

~

5.3 Other ways to adjust the access properties of base class members in derived classes

Derived classes can declare members with the same names as members of the base class. In the absence of virtual functions, if a member with the same name as the base class member is defined in the derived class, the derived class member is said to override the base class member with the same name. Using this name in the derived class means that the access is in the derived class. declared member. In order to use a member with the same name as the base class in a derived class, the member name must be preceded by the base class name and scope identifier "::", i.e.

base class name::member name

Access Statement

The way to access the declaration is to write the protected members or common members of the base class directly in the same-named segment in the definition of the private derived class, and prefix the member name with the base class name and scope identifier "::". Using this method, the member becomes a protected or shared member of the derived class.

class B:private A{ 
   
private:
    int y;
public:
    B(int x1, int y1) : A(x1) { 
   
        y = y1;
    }
    A::show;               //Access Statement
};
copy

The following points should be noted when using the access statement:

  1. Data members can also use access declarations.
  2. Access declarations contain only function or variable names without types and parameters.
  3. An access declaration cannot change a member's access attribute in the base class.
  4. For an overloaded function name of a base class, the access declaration will work on all functions of the same name in the base class.

~

5.4 Multiple inheritance

The general form for declaring a multiple inheritance derived class is as follows:

class derived class name:Inheritance 1 Base class name 1,...,Inheritance n base class name n { 
   
    New data members and member functions of derived classes
};
The default inheritance method is private
copy

Constructors and destructors of multiple inheritance derived classes:

Like single-inheritance derived class constructors, multiple-inheritance derived class constructors must also be responsible for calling all base class constructors for that derived class.

The calling sequence of multiple inheritance constructors is the same as the calling sequence of single inheritance constructors. It also follows the principle of calling the constructor of the base class first, then calling the constructor of the object members, and finally calling the constructor of the derived class. The invocation of the destructor does the opposite.

~

5.5 Virtual base classes

The role of virtual base classes: If a class has multiple direct base classes, and these direct base classes have a common base class, multiple copies of this indirect common base class data member will be retained in the lowest-level derived class member of the same name. When accessing these members with the same name, the direct base class name must be added after the derived class object name to uniquely identify a member to avoid ambiguity.

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

class Base{ 
   
protected:
	int a;
public:
	Base(){ 
   
		a = 5;
		cout << "Base a = " << a << endl;
	}
};

class Base1: public Base{ 
   
public:
	Base1() { 
   
		a = a + 10;
		cout << "Base1 a = " << a << endl;
	}
};

class Base2: public Base{ 
   
public:
	Base2() { 
   
		a = a + 20;
		cout << "Base2 a = " << a << endl;
	}
};

class Derived: public Base1, public Base2{ 
   
public:
	Derived() { 
   
		cout << "Base1::a = " << Base1::a << endl;
		cout << "Base2::a = " << Base2::a << endl;
	}
};

int main() { 
   
	Derived obj;
	return 0;
}
copy

The code execution result is as follows

Base a = 5
Base1 a = 15
Base a = 5
Base2 a = 25
Base1::a = 15
Base2::a = 25
copy

Declaration of virtual base class:

It is not difficult to understand that if there is only one copy of the class base in the above list (that is, there is only one data member a), then there will be no ambiguity in accessing a. In C++, this problem can be solved by declaring this public base class as a virtual base class. This requires that when a new class is derived from class base, use the keyword virtual to declare base as a virtual base class.

The syntax for declaring a virtual base class is as follows:

class Derived class:virtual Inheritance class name{ 
   
    ·····
};
copy

The above code is modified as follows:

class Base1:virtual public Base{ 
   
public:
	Base1() { 
   
		a = a + 10;
		cout << "Base1 a = " << a << endl;
	}
};

class Base2:virtual public Base{ 
   
public:
	Base2() { 
   
		a = a + 20;
		cout << "Base2 a = " << a << endl;
	}
};
copy

The results are as follows:

Base a = 5
Base1 a = 15
Base2 a = 35
Base1::a = 35
Base2::a = 35
copy

Initialization of virtual base class:

The initialization of a virtual base class is syntactically the same as the initialization of general multiple inheritance, but the order in which the constructors are called is different. The following points should be noted when using the virtual base class mechanism:

  1. If a constructor with formal parameters is defined in a virtual base class, and no constructor in default form is defined, then in the entire inheritance structure, all directly or indirectly derived classes must list the pair in the member initialization list of the constructor. A virtual base class constructor call to initialize data members defined in the virtual base class.
  2. When creating an object, if the object contains members inherited from the virtual base class, the members of the virtual base class are initialized by the constructor of the furthest derived class by calling the constructor of the virtual base class. Calls to the virtual base class constructor by other base classes of the derived class are automatically ignored.
  3. If the same level contains both virtual base classes and non-virtual base classes, the constructor of the virtual base class should be called first, then the constructor of the non-virtual base class, and finally the constructor of the derived class.
  4. For multiple virtual base classes, the execution order of constructors is still left-to-right, top-to-bottom.
  5. If a virtual base class is derived from a non-virtual base class, the base class constructor is still called first, and then the derived class constructor is called.

~

5.6 Assignment Compatibility Rules

Under certain conditions, type conversion can be performed between different types of data, for example, integer data can be assigned to double-precision variables. Before assigning, convert the integer data to double-precision data, and then assign it to the double-precision variable. This automatic conversion and assignment between different data types is called assignment compatibility. There is also an assignment compatibility relationship between the base class and the derived class object. The assignment compatibility rule between the base class and the derived class object means that wherever an object of the base class is needed, an object of the subclass can be used instead.

For example, the two classes declared below:

class Base{ 
   
    ·····
};
class Derived: public Base{ 
   
    ·····
};
copy

According to the assignment compatibility rules, wherever an object of the base class Base can be used, an object of the derived class Derived can be used instead, but only members inherited from the base class can be used. The specific performance is in the following aspects:

Six, polymorphism and virtual functions

Polymorphism is one of the important features of object-oriented programming. The polymorphism mechanism not only increases the flexibility of the object-oriented software system, further reduces redundant information, but also significantly improves the reusability and scalability of the software. The application of polymorphism can make programming more concise and convenient, and it also provides a means for the modular design of the program.

~

6.1 Overview of Polymorphisms

The so-called polymorphism is that when different objects receive the same message, different actions occur. In this way, you can use the same interface to access functions of different functions, thus realizing "one interface, multiple methods".

From an implementation perspective, polymorphism can be divided into two categories: compile-time polymorphism and run-time polymorphism. In C++, the implementation of polymorphism is related to the concept of linking. The so-called linking is the process of linking the function name and the program code of the function body together. Static build is the build done during the compile phase. Compile-time polymorphism is achieved through static linking. When statically compiling, the system uses actual parameters to match, and the overloaded functions with the same name are distinguished according to the difference in parameters, and then they are assembled, thus realizing polymorphism. Runtime polymorphism is implemented using dynamic binding. It is completed in the running phase during dynamic compilation, that is, when the program calls a certain function name, the program code is searched and connected. For object-oriented programming, it is only when the object receives a certain message. and connect the corresponding method.

Generally speaking, compiled languages ​​(such as C, Pascal) use static compilation, while interpreted languages ​​(such as LISP) use dynamic compilation. Static linking requires that all information about the calling function is known when the program is compiled. Therefore, the function call of this type of connection is fast and efficient, but it lacks flexibility; while the dynamic connection method is just the opposite. With this connection method, it is not until the program runs that it can determine which function to call, which reduces the The operating efficiency of the program is improved, but the flexibility of the program is enhanced. Pure object-oriented programming languages ​​can only use dynamic assembly because their execution mechanism is message passing. C++ actually uses a combination of static compilation and dynamic compilation.

In C++, compile-time polymorphism is mainly implemented through function overloading and operator overloading; run-time polymorphism is mainly implemented through virtual functions.

~

6.2 Virtual functions

The definition of the virtual function is carried out in the base class, and the keyword virtual is added to the declaration of the member function that needs to be defined as a virtual function in the base class, thereby providing an interface. The way to define a virtual function is as follows:

virtual return type function name(Formal parameter list) { 
   
    function body
}
copy

After a member function in a base class is declared virtual, the virtual function can be redefined in one or more derived classes. When a virtual function is redefined in a derived class, its function prototype, including return type, function name, number of parameters, and order of parameter types, must be exactly the same as the prototype in the base class.

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

class Family{ 
   
private:
	string flower;
public:
	Family(string name = "flowers"): flower(name) { 
    }
	string getName() { 
   
		return flower;
	}
	virtual void like() { 
   
		cout << "Family loves different flowers: " << endl;
	}
};

class Mother: public Family{ 
   
public:
	Mother(string name = "rose"): Family(name) { 
    }
	void like() { 
   
		cout << "mom likes" << getName() << endl;
	}
};

class Daughter: public Family{ 
   
public:
	Daughter(string name = "lily"): Family(name) { 
    }
	void like() { 
   
		cout << "daughter likes" << getName() << endl;
	}
};

int main() { 
   
	Family *p;
	Family f;
	Mother mom;
	Daughter dau;
	p = &f;
	p->like();
	p = &mom;
	p->like();
	p = &dau;
	p->like();

	return 0;
}
copy

The result of running the program is as follows:

Family loves different flowers:
mom likes roses
 daughter loves lily
copy

C++ stipulates that if a virtual function declaration is not explicitly given by virtual in the derived class, the system will follow the following rules to determine whether a member function is a virtual function: whether the function has a virtual function of the base class The same name, number of parameters, and corresponding parameter types, return types, or return types of pointers and references that satisfy assignment compatibility.

Here are some explanations for the definition of virtual functions:

  • Since the basis of the use of virtual functions is the assignment compatibility rule, the prerequisite for the assignment compatibility rule to be established is that the derived class is publicly derived from its base class. Therefore, when using the polymorphism mechanism by defining virtual functions, the derived class must publicly derive from its base class.
  • The virtual function must be defined in the base class first;
  • When the derived class redefines the virtual function declared in the base class, the keyword virtual can be written or not written.
  • Although virtual functions can also be called using object names and the dot operator, such as mom.like() can call the virtual function Mother::like(). However, this kind of call is statically compiled at compile time, it does not take full advantage of the characteristics of virtual functions, and only when the virtual function is accessed through the base class pointer can run-time polymorphism be obtained
  • No matter how many times a virtual function is publicly inherited, it still retains its virtual function characteristics.
  • A virtual function must be a member function of its class, not a friend function, nor a static member function, because a virtual function call depends on a specific object to determine which function to activate.
  • An inline function cannot be virtual because an inline function cannot dynamically determine its position on the fly. Even if a virtual function is defined inside a class, it is still considered non-inlined at compile time.
  • Constructors cannot be virtual, but destructors can and are usually declared virtual.

~

Redefining a virtual function of a base class in a derived class is another form of function overloading.

Multiple inheritance can be regarded as a combination of multiple single inheritances, so the virtual function call in the case of multiple inheritance is similar to the virtual function call under single inheritance.

~

6.3 Virtual destructors

If the new operator is used in the main function to create an unnamed object of a derived class and an object pointer that defines a base class, and the address of the unnamed object is assigned to the object pointer, when the delete operator is used to cancel the unnamed object, the system only executes the The destructor of the base class does not execute the destructor of the derived class.

Base *p;
p = new Derived;
delete p;
-----------------
Output: calling base class Base destructor of
copy

The reason is that when the unnamed object of the derived class pointed to by the pointer p is revoked and the destructor is called, the static linking method is used, and only the destructor of the base class Base is called.

If you want the program to perform dynamic compilation, when using the delete operator to delete the unnamed object of the derived class, first call the destructor of the derived class, and then call the destructor of the base class, you can declare the destructor of the base class as Virtual destructor. The general format is

virtual ~class name(){ 
   
    ·····
}
copy

Although the name of the destructor of the derived class is not the same as the name of the destructor of the base class, if the destructor of the base class is defined as a virtual function, the destructors of all derived classes derived from this class will also automatically become virtual. function. The example is as follows,

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

class Base{ 
   
public:
	virtual ~Base() { 
   
		cout << "call base class Base destructor of..." << endl;
	}
};

class Derived: public Base{ 
   
public:
	~Derived() { 
   
		cout << "call derived class Derived destructor of..." << endl;
	}
};

int main() { 
   
	Base *p;
	p = new Derived;
	delete p;
	return 0;
}
copy

The output is as follows:

call derived class Derived destructor of...
call base class Base destructor of...
copy

~

6.4 Pure virtual functions

A pure virtual function is a function that is "initialized to 0" when a virtual function is declared. The general form of declaring a pure virtual function is as follows:

virtual function type function name (parameter list) = 0;

After declaring it as a pure virtual function, the implementation part of the program is no longer given in the base class. The role of pure virtual function is to reserve a function name in the base class for its derived class, so that the derived class can redefine it as needed.

~

6.5 Abstract classes

If a class has at least one pure virtual function, then the class is called an abstract class. There are the following rules for the use of abstract classes:

  • Because the abstract class contains at least one pure virtual function with no defined function. Therefore, an abstract class can only be used as the base class of other classes, and cannot create abstract class objects.
  • Derivation of abstract classes from concrete classes is not allowed. A concrete class is an ordinary class that does not contain pure virtual functions.
  • An abstract class cannot be used as the parameter type of a function, the return type of a function, or the type of an explicit cast.
  • Polymorphism can be achieved by declaring a pointer or reference to an abstract class that can point to its derived classes.
  • If the derived class does not define the implementation of the pure virtual function, and the derived class only inherits the pure virtual function of the base class, the derived class is still an abstract class. If the implementation of the base class pure virtual function is given in the derived class, the derived class is no longer an abstract class, it is a concrete class that can create objects.

~

6.6 Example: Using Polymorphism to Calculate Area

Apply C++ polymorphism to calculate the area of ​​triangles, rectangles and circles.

#include <iostream>
using namespace std;

/*** define a common base class ***/
class Figure{ 
   
protected:
	double x, y;
public:
	Figure(double a, double b): x(a), y(b) { 
     }
	virtual void getArea()      //virtual function
	{ 
     
		cout << "No area computation defind for this class.\n";
	}
};

class Triangle: public Figure{ 
   
public:
	Triangle(double a, double b): Figure(a, b){ 
     }
	//Virtual function redefinition for finding the area of ​​a triangle
	void getArea(){ 
   
		cout << "Triangle with height " << x << " and base " << y;
		cout << " has an area of " << x * y * 0.5 << endl;
	}
};

class Square: public Figure{ 
   
public:
	Square(double a, double b): Figure(a, b){ 
     }
	//Virtual function redefinition for finding the area of ​​a rectangle
	void getArea(){ 
   
		cout << "Square with dimension " << x << " and " << y;
		cout << " has an area of " << x * y << endl;
	}
};

class Circle: public Figure{ 
   
public:
	Circle(double a): Figure(a, a){ 
     }
	//Virtual function redefinition for finding the area of ​​a circle
	void getArea(){ 
   
		cout << "Circle with radius " << x ;
		cout << " has an area of " << x * x * 3.14 << endl;
	}
};

int main(){ 
   
	Figure *p;
	Triangle t(10.0, 6.0);
	Square s(10.0, 6.0);
	Circle c(10.0);

	p = &t;
	p->getArea();
	p = &s;
	p->getArea();
	p = &c;
	p->getArea();

	return 0;
}
copy

The program output is as follows:

Triangle with height 10 and base 6 has an area of 30
Square with dimension 10 and 6 has an area of 60
Circle with radius 10 has an area of 314
copy

Seven, operator overloading

Operator overloading is an important feature of object-oriented programming.

~

7.1 Overview of operator overloading

Operator overloading is to assign multiple meanings to existing operators, so that the same operator acts on different types of data, resulting in different behaviors.

The following case implements overloading of the + operator:

#include <iostream>
using namespace std;

class Complex{ 
   
private:
	double real, imag;
public:
	Complex(double r = 0.0, double i = 0.0): real(r), imag(i) { 
    }
	friend Complex operator+(Complex& a, Complex& b) { 
   
		Complex temp;
		temp.real = a.real + b.real;
		temp.imag = a.imag + b.imag;
		return temp;
	}
	void display() { 
   
		cout << real;
		if (imag > 0) cout << "+";
		if (imag != 0) cout << imag << "i" << endl;
	}
};

int main()
{ 
   
	Complex a(2.3, 4.6), b(3.6, 2.8), c;
	a.display();
	b.display();
	c = a + b;
	c.display();
	c = operator+(a, b);
	c.display();

	return 0;
}
copy

The output of the program is as follows:

2.3+4.6i
3.6+2.8i
5.9+7.4i
5.9+7.4i
copy

~

This chapter is lazy 😁

Eight, function template and class template

Using the template mechanism can significantly reduce redundant information, greatly save program code, and further improve the reusability and maintainability of object-oriented programs. Template is a tool to realize code reuse mechanism. It can realize type parameterization, that is, define the type as a parameter, so as to realize the reuse of code, so that a program can be used to deal with many different types of objects, which greatly improves the program. design efficiency.

~

8.1 The concept of templates

There is often such a phenomenon in programming: the function bodies of two or more functions are exactly the same, and the difference is only with their parameter types.

E.g:

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

double Max(double x, double y) { 
   
    return x >= y ? x : y;
}
copy

Is it possible to write only one set of code for these functions? One way to solve this problem is to use a macro definition

#define Max(x, y)((x >= y) ? x : y)
copy

Another problem with macro definitions is that substitutions may be made where they should not be replaced, resulting in errors. In fact, macro definitions are not advocated in C++ because they cause a lot of trouble. Another way to solve the above problems is to use templates.

~

8.2 Function Templates

The so-called function template is actually to create a general function, whose function return type and formal parameter type are not specified, but represented by a virtual type. This general function is called a function template. When calling a function, the system will replace the virtual type in the template according to the type of the actual parameter (template argument), so as to realize the functions of different functions.

The declaration format of the function is as follows

template <typename type parameter>
return type function name(Template parameter list)
{ 
   
    function body
}
It can also be defined as the following form
template <class type parameter>
return type function name(Template parameter list)
{ 
   
    function body
}
copy

Actually, template is a keyword that declares a template, it means to declare a template. The type parameter (usually represented by C++ identifiers, such as T, type, etc.) is actually a virtual type name. It is not specified which specific type it is before use, but when using a function template, the type must be instantiated . The keyword typename or class needs to be added before the type parameter. The function of typename and class is the same.

Example 1: A function template related to pointers

#include <iostream>
using namespace std;

template <typename T>
T Max(T *array, int size = 0) { 
   
	T max = array[0];
	for (int i = 1	; i < size; i++) { 
   
		if (array[i] > max) max = array[i];
	}
	return max;
}

int main() { 
   
	int array_int[] = { 
   783, 78, 234, 34, 90, 1};
	double array_double[] = { 
   99.02, 21.9, 23.90, 12.89, 1.09, 34.9};
	int imax = Max(array_int, 6);
	double dmax = Max(array_double, 6);
	cout << "The maximum value of an integer array is:" << imax << endl;
	cout << "The maximum value of an array of doubles is:" << dmax << endl;
	return 0;
}
copy

Example 2: Overloading of function templates

#include <iostream>
using namespace std;

template <class Type>
Type Max(Type x, Type y) { 
   
	return x > y ? x : y;
}

template <class Type>
Type Max(Type x, Type y, Type z) { 
   
	Type t = x > y ? x : y;
	t = t > z ? t : z;
	return t;
}

int main() { 
   
	cout << "33,66 The maximum value is " << Max(33, 66) << endl;
	cout << "33,66,44 The maximum value is " << Max(33, 66, 44) << endl;
	return 0;
}
copy

Notice:

  • Multiple type parameters are allowed in function templates. However, it should be noted that each type parameter in the template definition section must be preceded by the keyword typename or class.
  • No other statements are allowed between the template statement and the function template definition statement.
  • Like regular functions, function templates can be overloaded.
  • A function template can be overloaded with a non-template function of the same name. In this case, the order of calling is: first look for a non-template function whose parameters match exactly, if found, call it; if not found, look for the function template, instantiate it, and produce a matching template parameter, If found, it is called.

~

8.3 Class Templates

The so-called class template, in fact, is to establish a general class, its data members, member function return type and formal parameter type are not specified, but represented by a virtual type. When using a class template to define an object, the system will replace the virtual type in the class template according to the type of the actual parameter, so as to realize the functions of different classes.

template <typename T>
class Three{ 
   
private:
    T x, y, z;
public:
    Three(T a, T b, T c) { 
   
        x = a; y = b; z = c;
    }
    T sum() { 
   
        return x + y + z;
    }
}
copy

In the above example, member functions (which have type parameters) are defined within the class body. However, member functions in a class template can also be defined outside the class template. At this point, if there are type parameters in member functions, C++ has some special provisions:

  1. Template declaration is required before member function definition;
  2. Add "class name <type parameter>::" before the member function name;

The general form of a member function defined outside a class template is as follows:

template <typename type parameter>
function type class name<type parameter>::member function name(Formal parameter list)
{ 
   
    ·····
}
copy

For example, in the above example, when the member function sum() is defined outside the class, it should be written as

template<typename T>
T Three<T>::sum() { 
   
    return x + y + z;
}
copy

**Example:**Use of stack class template

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

const int size = 10;
template <class T>
class Stack{ 
   
private:
	T stack[size];
	int top;
public:
	void init() { 
   
		top = 0;
	}
	void push(T t);
	T pop();
};

template <class T>
void Stack<T>::push(T t) { 
   
	if (top == size) { 
   
		cout << "Stack is full!" << endl;
		return;
	}
	stack[top++] = t;
}

template <class T>
T Stack<T>::pop() { 
   
	if (top == 0) { 
   
		cout << "Stack is empty!" <<endl;
		return 0;
	}
	return stack[--top];
}

int main() { 
   
	Stack<string> st;
	st.init();
	st.push("aaa");
	st.push("bbb");
	cout << st.pop() << endl;
	cout << st.pop() << endl;

	return 0;
}
copy

Nine, C++ input and output

~

9.1 Why C++ builds its own input/output system

In addition to fully supporting the input and output systems of the C language, C++ also defines a set of object-oriented input/output systems. The input and output system of C++ is more secure and reliable than that of C language.

C++'s input/output system is significantly better than C's input/output system. First, it is type-safe and prevents errors where the format controller does not match the type of input and output data. In addition, C++ can be used for user-defined types of input and output by overloading operators'>'and'<<', which is as effective and convenient as predefined types. The written form of C++ input/output is also very simple and clear, which makes the program code more readable.

~

9.2 C++ Streaming Library and Its Basic Structure

"Stream" refers to the abstraction of the flow of data from a source to a destination, which is responsible for establishing the connection between the producer of data (source) and the consumer of data (destination), and managing the flow of data. Any operation that transfers data from one place to another is a stream operation. Extracting data from a stream is called an input operation (usually called an extract operation), and adding data to a stream is called an output operation (usually called an insert operation). ).

C++ input/output is implemented in the form of byte streams. In an input operation, the stream of bytes flows from an input device (such as a keyboard, disk, network connection, etc.) to memory; in an output operation, a stream of bytes flows from memory to an output device (such as a monitor, printer, network connection, etc.). The byte stream can be ASCII code, data in binary form, graphics/image, audio/video and other information. Files and strings can also be viewed as ordered byte streams, called file streams and string streams, respectively.

~

Header files for input/output

The C++ compilation system provides an I/O class stream library for input/output. The I/O stream class library provides hundreds of input/output functions. The declarations of various classes in the I/O stream class library are placed in the corresponding header files. Users use the #include command to include the relevant headers in the program. The file is equivalent to declaring the classes that need to be used in this program. Commonly used header files are:

  • iostream contains the basic information needed to operate on input/output streams. This header file must be included when using stream objects such as cin and cout to perform I/O operations on standard devices.
  • fstream is used for user-managed file I/O operations. This header file must be included for operations on disk files using file stream objects.
  • strstream is used for I/O operations on string streams. This header file must be included when using string stream objects to perform I/O operations on the memory string space.
  • iomanip is used for format control of input/output. This header file must be included when most operators such as setw and fixed are used for format control.
Stream classes for input/output

The I/O Streams library contains many classes for input/output operations. Among them, class istream supports stream input operations, class ostream supports stream output operations, and class iostream supports both stream input and output operations.

The following table lists the commonly used stream classes in the iostream stream library, and indicates in which header file these stream classes are declared.

class name

class name

illustrate

head File

abstract stream base class

ios

Stream base class

iostream

input stream class

istream

Generic input stream class and base class for other input streams

iostream

input stream class

ifstream

input file stream class

fstream

input stream class

istrstream

Input string stream class

strstream

output stream class

ostream

Generic output stream class and base class for other output streams

iostream

output stream class

ofstream

output file stream class

fstream

output stream class

ostrstream

Output string stream class

strstream

input/output stream class

iostream

Base class for generic input/output streams and other input/output streams

iostream

input/output stream class

fstream

input/output file stream class

fstream

input/output stream class

strstream

Input/output string stream class

strstream

~

9.3 Predefined stream objects

Objects defined with streams are called stream objects. A stream object associated with an input device (such as a keyboard) is called an input stream object; a stream object associated with an output device (such as a screen) is called an output stream object.

C++ contains several predefined stream objects, which are the standard input stream object cin, the standard output stream object cout, the unbuffered standard error stream object cerr and the buffered standard error stream object clog.

~

9.4 Member functions of input/output streams

Use some member functions of istream and class ostream stream objects to realize the output and input of characters.

1,put()function
    cout.put(single character/glyph variable/ASCII code);
2,get()function
    get()Functions can include whitespace when reading in data, while the extraction operator ">>"Rejects whitespace by default.
    cin.get(character variable)
3,getline()function
    cin.getline(character array, number of characters n, Termination mark character)
    cin.getline(character pointer, number of characters n, Termination mark character)
4,ignore()function
    cin.ignore(n, termination character)
    ignore()The function of the function is to skip the input stream n characters (default is 1), or when the specified termination character is encountered(The default termination character is EOF)end early.
copy

~

9.5 Format Control for Predefined Type Input/Output

In many cases, it is necessary to control the input/output format of data of predefined types (such as int, float, double, etc.). In C++, you can still use the printf() and scanf() functions in C for formatting. In addition, C++ also provides two methods for format control: one is to use the stream member function related to format control in the ios class for format control; the other is to use a special type of function called operator for format control. Format control.

1. Use stream member functions for input/output format control

  1. Stream member function setf() that sets the status flag
  2. Stream member function unsetf() that clears the status flag
  3. The stream member function width() that sets the domain width
  4. Sets the precision of the real number stream member function precision()
  5. Stream member function fill() for fill characters

2. Use predefined operators for input/output format control

3. Use user-defined operators for input/output format control

If an operator function is defined for an output stream, the definition form is as follows:
ostream &operator name(ostream &stream)
{ 
   
    custom code
    return stream;
}

If an operator function is defined for an input stream, the definition form is as follows:
istream &operator name(istream &stream)
{ 
   
    custom code
    return stream;
}
copy

E.g,

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

ostream &output(ostream &stream)
{ 
   
	stream.setf(ios::left);
	stream << setw(10) << hex << setfill('-');
	return stream;
}

int main() { 
   
	cout << 123 << endl;
	cout << output << 123 << endl;
	return 0;
}
copy

The output is as follows:

123
7b--------
copy

~

9.6 File input/output

The so-called file generally refers to a collection of data stored on an external medium.

A file stream is a data stream that uses a stored file as an input/output object. The output file stream is the data that flows from the memory to the external storage file, and the input file stream is the data that flows from the external storage to the memory.

Depending on how the data in the file is organized, files can be divided into two categories: text files and binary files.

The general steps for file manipulation in C++ are as follows:

  1. Defines a stream object for the file to operate on.
  2. Create (or open) a file. If the file does not exist, create the file. Open the file if it already exists on disk.
  3. Perform read and write operations. Performs the required input/output operations on the basis of the created (or opened) file.
  4. Close the file. Open files should be closed when input/output operations are completed.

~

9.7 Opening and closing of files

To perform file input/output, C++ provides three file stream classes.

class name

illustrate

Function

istream

input file stream class

input for file

ofstream

output file stream class

output for file

fstream

input/output file stream class

for file input/output

These three file stream classes are defined in the header file fstream.

To perform file input/output, the following must be done:

  1. Include the header file fstream in your program.
  2. create stream object
  3. Use the member function open() to open the file.
  4. Perform read and write operations.
  5. Use the close() function to close open files.

~

9.8 Reading/writing text files

**Example:** Write the string "I am a student." to the disk file text.txt.

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

int main() { 
   
	ofstream fout("../test.txt", ios::out);
	if (!fout) { 
   
		cout << "Cannot open output file." << endl;
		exit(1);
	}
	fout << "I am a student.";
	fout.close();

	return 0;
}
copy

**Example:** Read the contents of the disk file test1.dat and display it on the screen.

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

int main() { 
   
	ifstream fin("../test.txt", ios::in);
	if (!fin) { 
   
		cout << "Cannot open output file." << endl;
		exit(1);
	}
	char str[80];
	fin.getline(str , 80);
	cout << str <<endl;
	fin.close();

	return 0;
}
copy

~

9.9 Reading and writing binary files

Read/write binary files with get() and put() functions

**Example:** Write the 26 English letters of a~z into a file, and then read and display them from the file.

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

int cput() { 
   
	ofstream outf("test.txt", ios::binary);
	if (!outf) { 
   
		cout << "Cannot open output file.\n";
		exit(1);
	}
	char ch = 'a';
	for (int i = 0; i < 26; i++) { 
   
		outf.put(ch);
		ch++;
	}
	outf.close();
	return 0;
}

int cget() { 
   
	fstream inf("test.txt", ios::binary);
	if (!inf) { 
   
		cout << "Cannot open input file.\n";
		exit(1);
	}
	char ch;
	while (inf.get(ch)) { 
   
		cout << ch;
	}
	inf.close();
	return 0;
}

int main() { 
   
	cput();
	cget();   //The file here can't be opened, I don't know why. . . 

	return 0;
}
copy
Read and write binary files with read() and write() functions

Sometimes it is necessary to read and write a set of data (such as the value of a structure variable). For this reason, C++ provides two functions read() and write() to read and write a data block. The most commonly used calling formats of these two functions are as follows :

inf.read(char *buf, int len);
outf.write(const char *buf, int len);
copy

**Example:** Store the course names and grades of two courses in a disk file in binary form.

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

struct list{ 
   
	char course[15];
	int score;
};

int main() { 
   
	list ob[2] = { 
   "Computer", 90, "History", 99};
	ofstream out("test.txt", ios::binary);
	if (!out) { 
   
		cout << "Cannot open output file.\n";
		abort();   //Exit the program, the effect is the same as exit.
	}
	for (int i = 0; i < 2; i++) { 
   
		out.write((char*) &ob[i], sizeof(ob[i]));
	}
	out.close();

	return 0;
}
copy

**Example:** The data stored in the disk file in the above example in binary form is read into memory.

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

struct list{ 
   
	char course[15];
	int score;
};

int main() { 
   
	list ob[2];
	ifstream in("test.txt", ios::binary);
	if (!in) { 
   
		cout << "Cannot open input file.\n";
		abort();
	}
	for (int i = 0; i < 2; i++) { 
   
		in.read((char *) &ob[i], sizeof(ob[i]));
		cout << ob[i].course << " " << ob[i].score << endl; 
	}
	in.close();

	return 0;
}
copy
Detect end of file

There is a flag at the end of the file, which is EOF. This terminator can be detected using the member function eof() when reading a file in file stream mode. If the return value of this function is non-zero, the end of file is reached. A return value of zero indicates that the end of file was not reached. The prototype of this function is:

int eof();
function eof()Examples of usage are as follows:
ifstream ifs;
···
if (!ifs.eof())   //end of file not reached
    ···
Another detection method is to check whether the stream object is nil, which means end of file.
ifstream ifs;
···
if (!ifs)
    ···
The following example:
while (cin.get(ch))
    cut.put(ch);
This is a very common method, which is to detect whether the return value of some member functions of the file stream object is 0, and 0 means that the stream (that is, the corresponding file) has reached the end.
copy

When inputting a character from the keyboard, its terminator is Ctrl+Z, that is to say, pressing the [Ctrl+Z] key combination, the value returned by the eof() function is true.

~

10. Exception Handling and Namespaces

10.1 Exception Handling

Misalignments commonly found in programs fall into two broad categories: compile-time errors and runtime errors. Compile-time errors are mainly syntax errors, such as misspelling of keywords, missing semicolons at the end of statements, mismatched parentheses, etc. Errors that occur at runtime are collectively referred to as exceptions, and the handling of exceptions is called exception handling.

C++ method for handling exceptions: If an exception occurs during the execution of a function, it can not be processed immediately in this function, but a message is sent to its upper level (that is, the calling function) to solve, if the upper level If the function cannot be processed, it will be passed to its upper level and processed by its upper level. Such a step-by-step upload, if it cannot be processed at the highest level, the operating system will generally automatically call the system function terminate(), which will call abort to terminate the program.

**Example:**Enter the lengths of the three sides of a triangle and find the area of ​​the triangle. When the length of the input side is less than 0, or when the three sides are all greater than 0 but cannot form a triangle, an exception is thrown and the program is terminated.

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

double triangle(double a, double b, double c) { 
   
	double s = (a + b + c) / 2;
	if (a + b <= c || a + c <= b || b + c <= a) { 
   
		throw 1.0;        //Statement throw throws double exception
	}
	return sqrt(s * (s - a) * (s - b) * (s - c));
}

int main() { 
   
	double a, b, c;
	try { 
   
		cout << "Please enter the lengths of the three sides of the triangle ( a, b, c): " << endl;
		cin >> a >> b >> c;
		if (a < 0 || b < 0 || c < 0) { 
   
			throw 1;   //The statement throw throws an int exception
		}
		while (a > 0 && b > 0 && c > 0) { 
   
			cout << "a = " << a << " b = " << b << " c = " << c << endl;
			cout << "area of ​​triangle = " << triangle(a, b, c) << endl;
			cin >> a >> b >> c;
			if (a <= 0 || b <= 0 || c <= 0) { 
   
				throw 1;
			}
		}
	} catch (double) { 
   
		cout << "These three sides cannot form a triangle..." << endl;
	} catch (int) { 
   
		cout << "side length is less than or equal to 0..." << endl;
	}
	return 0;
}
copy

~

10.2 Namespace and header file naming conventions

Namespace: An area of ​​memory named by the programmer. Programmers can specify some namespaces with names as needed, and associate the identifiers declared in each namespace with the identifiers of the namespaces to ensure that identifiers of the same name in different namespaces do not conflict.

1.Use of header files with extensions
 exist C Header files in language programs include extensions.h,Use the rules as the following example
    #include <stdio.h>
2.Use of header files without extension
C++The standard requires that system-provided header files do not include the extension.h,like string,string.h Wait.
    #include <cstring>
copy

Eleven, STL standard template library

Standard Template Library (Standard Template Library) contains many practical components, using these components, programmers programming is convenient and efficient.

11.1 Vector

A vector container is similar to an array, containing a group of storage units with contiguous addresses. Many operations can be performed on the vector container, including common operations such as query, insertion, and deletion.

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

int main() { 
   
	vector<int> nums;
	nums.insert(nums.begin(), 99);
	nums.insert(nums.begin(), 34);
	nums.insert(nums.end(), 1000);
	nums.push_back(669);

	cout << "\n current nums The element is: " << endl;
	for (int i = 0; i < nums.size(); i++)
		cout << nums[i] << " " ;

	cout << nums.at(2);
	nums.erase(nums.begin());
	nums.pop_back();

	cout << "\n current nums The element is: " << endl;
	for (int i = 0; i < nums.size(); i++)
		cout << nums[i] << " " ;

	return 0;
}
copy

~

11.2 The list container

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

int main() { 
   
	list<int> number;
	list<int>::iterator niter;
	number.push_back(123);
	number.push_back(234);
	number.push_back(345);

	cout << "Contents of the linked list:" << endl;
	for (niter = number.begin(); niter != number.end(); ++niter)
		cout << *niter << endl;
	number.reverse();
	cout << "The contents of the linked list after reversal:" << endl;
	for (niter = number.begin(); niter != number.end(); ++niter)
		cout << *niter << endl;
	number.reverse();

	return 0;
}
copy

~

11.3 stack

**Example:**Use stack for base conversion

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

int main() { 
   
	stack<int> st;
	int num = 100;
	cout << "100 The octal representation is:";
	while (num) { 
   
		st.push(num % 8);
		num /= 8;
	}
	int t;
	while (!st.empty()) { 
   
		t = st.top();
		cout << t;
		st.pop();
	}
	cout << endl;

	return 0;
}
copy

~

11.4 queue

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

int main() { 
   
	queue<int> qu;
	for (int i = 0; i < 10; i++) 
		qu.push(i * 3 + i);
	while (!qu.empty()) { 
   
		cout << qu.front() << " ";
		qu.pop();
	}
	cout << endl;

	return 0;
}
copy

~

11.5 Priority queue priority_queue

#include <iostream>
#include <queue>
#include <functional>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() { 
   
	priority_queue<int> pq;
	srand((unsigned)time(0));
	for (int i = 0; i < 6; i++) { 
   
		int t = rand();
		cout << t << endl;
		pq.push(t);
	}
	cout << "The value of the priority queue:" << endl;
	for (int i = 0; i < 6; i++) { 
   
		cout << pq.top() << endl;
		pq.pop();
	}

	return 0;
}
copy

~

11.6 Deques

push_back();
push_front();
insert();
pop_back();
pop_front();
erase();
begin();
end();
rbegin();
rend();
size();
maxsize();
copy

~

11.7 set

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

int main() { 
   
	set<string> s;
	s.insert("aaa");
	s.insert("bbb");
	s.insert("ccc");
	if (s.count("aaa") != 0) { 
   
		cout << "element of existence aaa" << endl;
	}
	set<string>::iterator iter;
	for (iter = s.begin(); iter != s.end(); ++iter) 
		cout << *iter << endl;

	return 0;
}
copy

~

11.8 map

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

int main() { 
   
	map<string, int> m;
	m["aaa"] = 111;
	m["bbb"] = 222;
	m["ccc"] = 333;
	if (m.count("aaa")) { 
   
		cout << "key aaa The corresponding value is" << m.at("aaa") << endl;
		cout << "key aaa The corresponding value is" << m["aaa"] << endl;
	}

	return 0;
}
copy

The blogger simply summarizes the knowledge points during the review process for later review and learning. Note: This blog is for learning and reference only. It has a lot of content, and there will inevitably be mistakes. Please bear with me. Please inform if there is any infringement. Reference material "C++ Object-Oriented Programming" edited by Chen Weixing and Lin Xiaocha

Publisher: full stack programmer, please indicate the source: https://javaforall.cn/152073.html Original link: https://javaforall.cn

Posted by mady on Sat, 10 Sep 2022 22:15:51 +0530