Xi'an Petroleum University C++ final exam key knowledge points + topic review (Part 1)

insert image description here

Chapter One

Usage of the "const" keyword

Here are some code examples when using constto modify variables, function parameters, member functions, and pointers:

  1. Declare read-only variables:
const int MAX_VALUE = 100;
const float PI = 3.14;
  1. Protection function parameters:
void printArray(const int arr[], int size) {
    
    
    // 不会修改 arr[] 中的值
    for (int i = 0; i < size; i++) {
    
    
        cout << arr[i] << " ";
    }
}
  1. Prevent member functions from modifying object state:
class MyClass {
    
    
public:
    void display() const {
    
    
        // 不会修改对象的数据成员
        cout << "Value: " << value << endl;
    }

private:
    int value;
};
  1. Prevent pointers from modifying the pointed-to value:
void printString(const char* str) {
    
    
    // 不会修改 str 指向的字符数组
    cout << str << endl;
}

int main() {
    
    
    const char* message = "Hello, World!";
    printString(message);
}

These examples show how to use constthe keyword to declare constants, protect function parameters, prevent member functions from modifying object state, and prevent pointers from modifying the value they point to. Used in appropriate places const, it can improve the readability of the code and ensure the immutability of the data.

1) 定义常量
const int MAX_VAL = 23const string SCHOOL_NAME = "Peking University"1) 定义常量指针

int n,m;
const int * p = & n;
* p = 5; 
n = 4; 
p = &m; 

1) 定义常量指针

不可通过常量指针修改其指向的内容
int n,m;
const int * p = & n;
* p = 5; //编译出错
n = 4; 
p = &m; 



int n,m;
const int * p = & n;
* p = 5; //编译出错
n = 4; //ok
p = &m; 
35

int n,m;
const int * p = & n;
* p = 5; //编译出错
n = 4; //ok
p = &m; //ok, 常量指针的指向可以变化



不能把常量指针赋值给非常量指针,反过来可以

const int * p1; int * p2;
p1 = p2; //ok
p2 = p1; //error
p2 = (int * ) p1; //ok,强制类型转换




函数参数为常量指针时,可避免函数内部不小心改变
参数指针所指地方的内容

void MyPrintf( const char * p )
{
    
    
strcpy( p,"this"); //编译出错
printf("%s",p); //ok
}

2) 定义常引用

不能通过常引用修改其引用的变量

int n;
const int & r = n;
r = 5; //error
n = 4; //ok

const and define comparison

constand #defineare two different ways to define constants, they have the following main differences and comparison points:

  1. Type safety:

    • constis a keyword in C++, which can define a constant as a specific data type. It provides type safety, the compiler can check that the types match and avoid accidental data type errors.
    • #defineis a C/C++ preprocessing directive, which is simply text replacement. When using #defineto define constants, there is no type checking, which may lead to potential type errors.
  2. scope:

    • constCan be scoped to a specific scope, such as inside a function, class, or namespace. This controls the visible scope of the constant.
    • #defineDefined constants have no scope and are substituted throughout the file, potentially leading to naming conflicts and unexpected substitution errors.
  3. Calculated at compile time:

    • constCan contain compile-time evaluated expressions, eg const int MAX_VALUE = 10 * 5;.
    • #defineOnly text replacement can be done, compile-time evaluation is not supported.
  4. Debugging and readability:

    • Constants defined with constthe keyword have debug symbol table information, and their values ​​can be viewed in a debugger.
    • #defineDefined constants do not appear in the symbol table, and constant values ​​may not be easily tracked when debugging.

To sum up, it is recommended to use the keyword to define constants first in C++ const. It provides type safety, scope control, compile-time evaluation, and better readability and debugging support. #defineIt is mainly used to define macros, not constants, and should be used with caution, and it is more preferred to use constto define constants.

usage of return

returnis a keyword used to return a value from a function or terminate function execution prematurely. It has several usages:

  1. return value:

    • When declaring and defining a function, you can specify the return type of the function, and use the statement in the function body returnto return a value.
    • For example, after doing some computation in a function, use returnto return the result of the computation to the caller.
    int add(int a, int b) {
          
          
        return a + b;
    }
    
  2. Terminate function execution early:

    • During function execution, you can use returnto end the execution of the function early, no matter whether there is a return value or not.
    • For example, you can use to exit a function immediately when a certain condition is met return.
    void processArray(const int arr[], int size) {
          
          
        for (int i = 0; i < size; i++) {
          
          
            if (arr[i] == 0) {
          
          
                return;  // 满足条件则提前结束函数执行
            }
            // 继续处理数组元素...
        }
    }
    
  3. Return reference type (C++):

    • In C++, in addition to returning values ​​of primitive data types and user-defined types, reference types can also be returned.
    • By returning a reference, you can use the return value of a function as an lvalue and modify the value of the original variable.
    int& getValue(int& num) {
          
          
        return num;  // 返回 num 的引用
    }
    
    int main() {
          
          
        int x = 5;
        getValue(x) = 10;  // 将返回的引用作为左值,修改 x 的值为 10
        cout << x;        // 输出:10
        return 0;
    }
    

Regardless of the circumstances, returnthe keyword can be used to end the execution of a function and return control to the caller. When writing a function, make sure to conform to the return value type defined by the function, and use to returnguide the flow of the function as needed.

returnThere are a few more caveats and usage to know when it comes to the keyword:

  1. voidUse in the function :

    • voidA function is a function that does not return a value. In this case, returnit can be used to explicitly end the execution of a function prematurely, without any return value.
    void printMessage() {
          
          
        cout << "Hello, world!" << endl;
        return;  // 提前结束函数执行
        cout << "This line will not be executed.";
    }
    
  2. Multiple return points for functions:

    • Functions can use returnthe keyword in multiple places to return different values. Multiple return points can be used to improve the readability and flexibility of your code, based on conditional or logical requirements.
    int getMax(int a, int b) {
          
          
        if (a > b) {
          
          
            return a;
        } else {
          
          
            return b;
        }
    }
    
  3. Return array or pointer:

    • In a function, you can use returnthe keyword to return a pointer to an array or a pointer. But be aware that when returning pointers to local variables, great care must be taken to avoid returning invalid pointers.
    int* createArray(int size) {
          
          
        int* arr = new int[size];
        // 初始化数组...
        return arr;
    }
    
    void deleteArray(int* arr) {
          
          
        delete[] arr;
    }
    
  4. In a loop use return:

    • Use in a loop returnto end the loop prematurely and return the function.
    • For example, when looking for a specific element, you can use to returnend the loop as soon as the element is found.
    bool containsValue(const int arr[], int size, int value) {
          
          
        for (int i = 0; i < size; i++) {
          
          
            if (arr[i] == value) {
          
          
                return true;  // 找到元素,提前结束循环
            }
        }
        return false;  // 循环结束,未找到元素
    }
    

In short, returnkeywords play an important role in functions, and they can be used to return values, end function execution early, return different values ​​at different locations, and even return pointers or arrays. Reasonable and correct use returncan make the function code more clear, flexible and easy to maintain.

function overloading

One or more functions with the same name but different number or types of parameters is called function overloading.

以下三个函数是重载关系:
int Max(double f1,double f2) {
    
     }
int Max(int n1,int n2) {
    
     }
int Max(int n1,int n2,int n3) {
    
     }

Function overloading makes function naming easy.

The compiler judges which function should be called according to the number and type of actual parameters in the call statement.
Here is a simple example showing how to use function overloading to implement addition of different data types:

#include <iostream>

// 加法运算:两个整数相加
int sum(int a, int b)
{
    return a + b;
}

// 加法运算:两个浮点数相加
double sum(double a, double b)
{
    return a + b;
}

int main()
{
    // 整数相加
    int x = 5;
    int y = 10;
    std::cout << "sum of " << x << " and " << y << " is " << sum(x, y) << '\n';

    // 浮点数相加
    double d1 = 2.5;
    double d2 = 3.7;
    std::cout << "sum of " << d1 << " and " << d2 << " is " << sum(d1, d2) << '\n';

    return 0;
}

In this example, we define two sumfunctions with the same name, but with different types of input parameters. They are integer and floating point respectively, so that function overloading can be used to realize the processing and calculation of different types of data.

Function default parameters

In C++, when defining a function, you can let the rightmost consecutive parameters have default values, then when calling the function, if no parameter is written in the corresponding position, the parameter is the default value

void func( int x1, int x2 = 2, int x3 = 3) 
{
    
     }
func(10 ) ; //等效于 func(10,2,3)
func(10,8) ; //等效于 func(10,8,3)
func(10, , 8) ; //不行,只能最右边的连续若干个参数缺省

The purpose of function parameters being default is to improve the scalability of the program.

That is, if a written function needs to add new parameters, but the original statements that call the function may not need to use the new parameters, then in order to avoid modifying the original function call statements, you can use the default parameters.

inline function

Function calls have time overhead. If the function itself has only a few statements, the execution is very fast, and the function is executed repeatedly many times, the overhead of calling the function will appear relatively large in comparison.

In order to reduce the overhead of function calls, an inline function mechanism is introduced. When the compiler processes the calling statement of the inline function, it inserts the code of the entire function into the calling statement, and does not generate a statement calling the function.

1.inline int Max(int a,int b)
{
    
    
if( a > b) return a;
return b;
}

2.下面是一个简单的示例,展示如何使用内联函数来计算两个整数之和:

```c++
#include <iostream>
inline int sum(int a, int b) // 定义内联函数
{
    
    
    return a + b; // 直接返回两数之和
}
int main()
{
    
    
    int x = 5;
    int y = 10;
    std::cout << "sum of " << x << " and " << y << " is " << sum(x, y) << '\n';

    return 0;
}
在编译期间,编译器通过将`sum()`函数的代码插入到主程序中,来避免函数调用时发生额外的开销。此外,由于此函数的代码块非常简短,因此提高效率的作用更加明显。

1.1 Fill in the blanks

(1) There must be a function named main in a complete runnable program . (2) An expression statement must end with a semicolon . (3) A function definition consists of two parts: the function header and the function body. (5) The extensions of the C++ language header file and source program file are .h CPP respectively. (7) When the Void reserved word is used as the function type, the function does not return any value. (8) When the function parameter table is represented by the Void reserved word, it means that the parameter table is empty. (9) From a function prototype statement "intfun1(void);", it can be seen that the return type of this function is 13, and this function has more than 0 parameters. (10) The header files included in the #include command can be system-defined header files or user-defined header files. differs from other functions of the same name. (12) If there are multiple default parameters in a function, the default parameters must all be in the part of the formal parameter table. (13) The scope of the function parameter is the local scope of the function (14) When defining a structure variable, the memory size allocated by the system to the variable is equal to the sum of the memory size L required by each member

Exercises after class (1)

insert image description here
insert image description here
The format for accessing apublic member variables of an object is .xa.x

Assuming that the defined class Ahas public member variables x, by creating an object Aof class a, we can use the object name afollowed by the member access operator ., followed by the member variable name x, to access the member variable.

The sample code is as follows:

class A {
    
    
public:
    int x;
};

int main() {
    
    
    A a;
    a.x = 10;  // 访问对象 a 的成员变量 x,并赋值为 10
    return 0;
}

In the above example, we defined a class Awith public member variables x. In main()the function, we create Aan object of the class a, then access the member variable of a.xthe object through , and assign it a value of 10.ax

It should be noted that when accessing a member variable of an object, you should ensure that the access modifier of the member variable allows access in the current scope. If a member variable xis private or protected, it cannot be accessed directly through the object name, but needs to be accessed indirectly through a public member function.

A class's constructor is called automatically when an ( object ) of that class is defined.

For any class, the number of constructors that users can define is at most ( ).
For any class, the number of constructors that users can define is at most infinite.

In C++, a class can have multiple constructors, and users can define multiple constructors to initialize different properties of objects as needed. Constructors are used to initialize member variables of an object or perform other necessary operations when an object is created. User-defined constructors can have different parameter lists to allow different parameter values ​​to be supplied when the object is created.

For example, a class can have a default constructor (no parameter), a constructor with one parameter, a constructor with multiple parameters, and so on. In this way, users can choose the appropriate constructor to create objects according to different situations and needs.

Here is an example showing a class Personwith multiple constructors:

#include <iostream>
using namespace std;

class Person {
    
    
public:
    string name;
    int age;

    // 默认构造函数
    Person() {
    
    
        name = "Unknown";
        age = 0;
    }

    // 带参数的构造函数
    Person(string n, int a) {
    
    
        name = n;
        age = a;
    }
};

int main() {
    
    
    Person p1;             // 使用默认构造函数
    cout << p1.name << endl;  // 输出: Unknown
    cout << p1.age << endl;   // 输出: 0

    Person p2("Alice", 25);  // 使用带参数的构造函数
    cout << p2.name << endl;  // 输出: Alice
    cout << p2.age << endl;   // 输出: 25

    return 0;
}

In the above example, the class Personhas two constructors: a default constructor and a parameterized constructor. Users can choose to use the appropriate constructor to create the object, and initialize the member variables of the object according to the definition of the constructor.

Therefore, for any class, users can define multiple constructors, and there is no limit to the number.

When an automatic object leaves its scope, the system automatically calls the class's destructor.

In C++, a destructor is a special member function that is called automatically when an object is destroyed. Its role is to perform some cleanup work at the end of the object life cycle, such as releasing dynamically allocated memory, closing files, and so on. The name of the destructor is the same as the class name, prefixed with a tilde (~).

When an automatic object leaves its scope (for example, a function finishes executing, a code block ends), the system automatically calls the destructor of the class to ensure proper release and cleanup of resources.

Here is an example showing a class Personwith a destructor:

#include <iostream>
using namespace std;

class Person {
    
    
public:
    string name;

    // 构造函数
    Person(string n) {
    
    
        name = n;
        cout << "构造函数被调用 - " << name << endl;
    }

    // 析构函数
    ~Person() {
    
    
        cout << "析构函数被调用 - " << name << endl;
    }
};

int main() {
    
    
    {
    
    
        Person p1("Alice");  // 创建自动对象 p1
        Person p2("Bob");    // 创建自动对象 p2
    }  // p1 和 p2 在这里离开作用域,调用析构函数

    return 0;
}

In the above example, the class Personhas a constructor and a destructor. Inside the code block in main()the function, we create two automatic objects p1and p2, which respectively go out of scope when the scope ends. When these two objects go out of scope, the system automatically calls their corresponding destructors. The order in which constructors and destructors are called can be seen in the console output.

Therefore, when an automatic object leaves its scope, the system will automatically call the destructor of the class to complete the cleanup of resources.

//Destructors destructors

The name is the same as the class name, add '~' in front, there are no parameters and return values, and a class can only have one destructor at most.

The destructor is called automatically when the object dies. You can define a destructor to do aftermath work before the object dies, such as releasing the allocated space.

If no destructor is written when defining a class, the compiler generates a default destructor. The default destructor does nothing.

If a destructor is defined, the compiler does not generate a default destructor.

The destructor is a special function corresponding to the constructor, which is mainly used to clean up the memory resources occupied by the object at the end of the object life cycle.

In C++, each class can define its own destructor, which ~consists of a tilde and the class name, and requires no parameters or return value. Usually, operations that need to clean up dynamically allocated memory, close open files, release network connections, etc. can be implemented in the destructor.

In the sample code below, we define a Personclass called , which contains two member variables nameand age, and we define a simple destructor in this class that outputs a message when the object is destroyed:

#include<iostream>
using namespace std;

class Person {
    
    
public:
    string name;
    int age;
    Person(string n, int a): name(n), age(a) {
    
     // 构造函数
        cout << "Object created." << endl;
    }
    ~Person(){
    
                                     // 析构函数
        cout << "Object destroyed." << endl;
    }
};

int main() {
    
    
    Person p1("张三", 20);
    return 0;
}

In the above code, we defined an Personobject p1and initialized its properties (name and age). After main()the function ends, the program finishes running, that is, when the life cycle of Personthe object p1ends, the destructor will be called automatically ~Person()to release the occupied memory resources. In this destructor, we simply output a message "Object destroyed.".

In short, the destructor is a special function of the class, which is automatically called (or manually called) at the end of the object life cycle. Its main function is to clean up the resources occupied by the object, such as dynamically allocated memory, open files, etc. With the help of destructors, we can better control the way the program uses memory resources and avoid problems such as memory leaks.

Why do we need a destructor

In C++, we often use dynamic memory allocation to create objects, such as using newkeywords to allocate memory space for an object. Since this part of the dynamically allocated memory space needs to be released after the program finishes running, we need to use deletekeywords to release these memory spaces.

If we do not release these memory reasonably, after a period of program execution, the physical memory of the machine will be exhausted, causing the system to crash or the efficiency of the program to decrease. Therefore, in order to avoid problems such as memory leaks, we can use the destructor to release the occupied memory resources.

In addition, another important role of the destructor is to help us manage various data structures and states in the class. Usually we can use the destructor to release resources, but it should be noted that in most cases, the destructor is automatically called when the object is destroyed, and the programmer does not need to call it manually.

To sum up, the destructor exists to solve the problem of dynamic memory application and management in the program. It is a special function that is automatically called when the object life cycle ends, and is mainly used to clean up the resources occupied by the object. , restore the state of the object, etc. The use of destructors can effectively manage memory resources and prevent memory leaks and other related problems. Assuming that Student is a class, a dynamic object ( * s
insert image description here
) is obtained when the statement "Student *s = new Student(a, 20);" is executed . Executing the statement will get a dynamic object, and this dynamic object can be accessed and manipulated through the pointer.
Student *s = new Student(a, 20);s

Specifically, new Student(a, 20)this expression will call Studentthe constructor of the class passing the parameters aand 20. It then allocates memory on the heap to store the Studentobject and returns a pointer to that object. This pointer is assigned to the variable s, thus spointing to the created dynamic object.

By dereferencing a pointer s, i.e. using *s, it is possible to obtain the dynamic object itself, not a pointer to it. Thus, *srepresenting this dynamic object itself.

For example, you can use to (*s).methodName()call methods of dynamic objects, or use (*s).memberVariableto access member variables of dynamic objects.

It should be noted that when the dynamic object is no longer needed, deletethe operator should be used to release the memory it occupies. For example, you can use delete s;to free the dynamic objects and associated memory created in the above example.

Therefore, the statement is executed Student *s = new Student(a, 20);to obtain a dynamic object, which can be *saccessed and manipulated through .

The result of the following program is ( ).

#include <iostream.h>

void main(void)

{

 int a(50), &b = a;



 cout << "b=" << b << endl;

 a+=50;

 cout<<"b="<<b<<endl;

 b+=80;

 cout<<"a="<<a<<endl;

}

This program has some issues and won't compile. The main problem is that outdated header files are used <iostream.h>, where the correct header files should be <iostream>.

Also, void main(void)is a non-standard mainway of defining a function and should be changed to int main().

Here is the revised program:

#include <iostream>

int main()
{
    
    
    int a(50), &b = a;

    std::cout << "b=" << b << std::endl;

    a += 50;
    std::cout << "b=" << b << std::endl;

    b += 80;
    std::cout << "a=" << a << std::endl;

    return 0;
}

The corrected program output is:

b=50
b=100
a=180

The explanation is as follows:

  • First, ainitialize the variable to 50, and create a reference bto make it a reference a.
  • The output bvalue is 50.
  • aAdd 50 to to change athe value of to 100.
  • The value of output bis 100, because bis aa reference to , so as achanges in , bthe value of will also change.
  • By badding 80 to , athe value of is changed to 180, and for the same reason, bthe value of is also changed accordingly.
  • The output avalue is 180.

Therefore, the result of running the program is:

b=50
b=100
a=180
假定要求下面程序的输出结果为“11/15,其主函数中存在着三行语句错误,请指出错误语句行的行号。

#include <iostream.h>



class Franction {
    
      

	int nume;  

	int deno;  

public:

	InitFranction() {
    
    nume=0; deno=1;}

   void InitFranction(int n, int d) {
    
    nume=n; deno=d;}



	void FranSimp();  

	Franction FranAdd(const Franction& x);  

	void FranOutput()

	{
    
    

		cout<<nume<<'/'<<deno<<endl;

	}

};

void main()              			 						

{
    
                         											

  		Franction a,b,c;           						 //1行

		a.InitFranction(6,15);      						 //2行

		b.InitFranction(1);           						 //3行		         

		c=FranAdd(a,b);              					 //4行

		cout<<c.nume<<'/'<<c.deno<<endl;  	 //5行

} 

The following is to point out the errors in the program:

  1. Line 2: #include <iostream.h>is wrong, should be #include <iostream>. The correct header file should be <iostream>.

  2. Line 13: InitFranction()should be changed to Franction(), to match the class name. The function name and class name should be the same to be used as a constructor.

  3. Line 25: void main()should be changed to int main(). The main function must return an integer value.

  4. Line 32: c = FranAdd(a, b);is wrong and should be replaced c = a.FranAdd(b);. FranAdd()is Franctiona member function of the class and should be called through the object.

The corrected code is as follows:

#include <iostream>

class Franction {
    
    
    int nume;
    int deno;

public:
    Franction() {
    
     nume = 0; deno = 1; }
    void InitFranction(int n, int d) {
    
     nume = n; deno = d; }

    void FranSimp();
    Franction FranAdd(const Franction& x);
    void FranOutput()
    {
    
    
        std::cout << nume << '/' << deno << std::endl;
    }
};

int main()
{
    
    
    Franction a, b, c;
    a.InitFranction(6, 15);
    b.InitFranction(1);
    c = a.FranAdd(b);
    std::cout << c.nume << '/' << c.deno << std::endl;
    return 0;
}

At this point, the program will output 11/15.

下面程序是有问题的,请指出需要修改哪三行?

#include <iostream.h>



class CE{
    
    

	int a,b;              									 

public:                   

    int c;                									

	void SetValue(int x1,int x2, int x3) 		

    {
    
    

         a=x1; b=x2; c=x3;       					 

	}                   

	int GetMin();          								  //1行

};                     

int GetMin()												  //2行

{
    
                

	return (a < b ? a : b);   					     //3行

} 

void main()

{
    
    

	CE test;												  //4行

	test.SetValue(1, 2, 3);							  //5行

	c = GetMin();						  				  //6行

	cout<<c<<endl;									  //7行

}
  1. Line 6: int c;is the wrong place, it should be placed publicafter the access identifier inside the class definition.

  2. Inside CEthe class, the declaration of the function should GetMin()be moved from where it was commented to the correct location, after the SetValue()function declaration.

  3. Outside CEthe class, GetMin()the definition of the function should be changed to a member function form, and the class name is added before the function name CE::.

The corrected code is as follows:

#include <iostream>

class CE {
    
    
    int a, b;

public:
    int c;

    void SetValue(int x1, int x2, int x3)
    {
    
    
         a = x1; b = x2; c = x3;
    }

    int GetMin();
};

int CE::GetMin()
{
    
    
    return (a < b ? a : b);
}

int main()
{
    
    
    CE test;
    test.SetValue(1, 2, 3);
    int c = test.GetMin();
    std::cout << c << std::endl;
    return 0;
}

At this point, the program will output 1.
Function overloading means that in the same scope, multiple functions with the same function name but different parameter lists can be defined. The purpose of this is to provide a more flexible function calling method to adapt to different parameter types or parameter numbers.

Features of function overloading include:

  1. Same function name: Overloaded functions have the same function name.
  2. Different parameter lists: The parameter lists of overloaded functions must be different, which can be different parameter types, different numbers of parameters, or different order of parameters.
  3. The return value type is not a condition for overloading: the return value types of overloaded functions can be the same or different.
  4. In the same scope: Overloaded functions must be defined in the same scope.

Function overloading allows us to define functions with similar functions but different parameter types or number of parameters, which makes the code more concise, more readable, and provides better flexibility and ease of use.

** int function(char*x) char p=x;while(p++);return(p-x-1);

The return result is to find the length of the string

Based on the code you provided, int function(char *x)the implementation of the function is as follows:

int function(char *x) {
    
    
    char *p = x;
    while (*p++) ;
    return (p - x - 1);
}

This function will accept a xcharacter pointer named as a parameter. It first xassigns to the pointer variable p, and then loops through the character array pointed to by the whilepointer until it reaches the end of the string (that is, the null character ). After the loop ends, the function will return the length of the string, which is the position pointed to by the last pointer minus the position of the start pointer and minus 1 (because the trailing null character is excluded).p\0px

Note that this function assumes that the char pointer passed in xis a valid null-terminated string. If the parameters passed in do not meet this condition, unexpected results or errors may result. When using this function, make sure to pass in the correct parameters.

The role of overloaded functions
The role of function overloading mainly has the following aspects:

  1. Provide more flexible function calling methods: through function overloading, function versions with different parameter types or number of parameters can be provided for the same operation. In this way, the caller can select the most suitable function to call according to the need, without having to remember multiple different function names.

  2. Enhances code readability and maintainability: By having functions with the same name but different parameter lists, you can make your code clearer and more understandable. Function overloading can be used to represent similar functions but different operation objects or parameter types, thereby improving the readability and maintainability of the code.

  3. Avoid function naming conflicts: When functions with similar functions need to be implemented, since function names are unique identifiers, using different function names may cause conflicts. Through function overloading, the same function name can be used in the same scope, and they can be distinguished by different parameter lists, avoiding naming conflicts.

  4. Reduce duplication of similar function codes: When operations with similar functions need to be implemented multiple times, these operations can be integrated under the same function name through function overloading. This reduces duplication of code and improves code reusability and maintainability.

All in all, function overloading can provide more flexible function calling methods, enhance the readability and maintainability of code, avoid function naming conflicts, and reduce the existence of repeated code. By properly using function overloading, you can make your code more concise, flexible, and easy to understand.

#include
#include

void f(int *p, int n) {
for (int i = 0; i < n; i++) {
(*p)++;
}
}

int main() {
int i, a[] = {0, 1, 2, 3, 4};
int *p = &a[0];
f(p, 2);

for (i = 0; i < 5; i++) {
    std::cout << a[i];
}

return 0;

}

When this code is executed, the following steps are executed:

  1. At the beginning of the function, an integer variable , an integer array and an integer pointer pointing to the array are maindefined . Array is initialized with pointer pointing to the first element of array .iaapa{0, 1, 2, 3, 4}pa

  2. Call the function f(p, 2), passing the pointer pand the parameter value 2to the function f.

  3. Enter the function f, define an integer variable inside the function i, and use a loop to perform an auto-increment operation foron athe first element of the array. nIn this example, since nthe value of is 2, the loop iterates twice, and the operation ais performed on the first element of the array , that is, the value pointed to by the pointer is incremented by 1. Therefore, the array becomes .(*p)++pa{2, 1, 2, 3, 4}

  4. After the function ffinishes executing, return to mainthe function.

  5. In mainthe function, use forto loop through aall the elements of the array and use to std::coutoutput the value of each element. Therefore, the output is 11234.

  6. Finally, mainthe function ends, the return value is 0, and the program execution is complete.

Final result 21234

Function definitions cannot be nested, function calls can be nested

new delete usage

newand deleteare keywords in C++ for dynamically allocating and freeing memory.

newIt is used to dynamically create a single object or a continuous memory space, and return the pointer of the object or memory block. Its syntax is as follows:

T* pointer = new T;
T* array = new T[size];

where Tis the type of object to be allocated, pointeris a pointer to a newly allocated single object, arrayis a pointer to a newly allocated array of contiguous objects, and sizeis the size of the array.

Example:

int* p = new int; // 动态分配一个 int 类型的对象,返回指向该对象的指针
int* arr = new int[5]; // 动态分配一个包含 5 个 int 类型对象的数组,返回指向数组的指针

After newallocating memory, you can access and manipulate the allocated objects or arrays through pointers.

Correspondingly, deleteis used to free newmemory space allocated via so that it can be returned to the system. Its syntax is as follows:

delete pointer;
delete[] array;

where pointeris a pointer to a single object to be freed and arrayis a pointer to an array of objects to be freed. Note that if new[]an array is allocated via , it must be delete[]deallocated using .

Example:

int* p = new int; // 使用 new 分配内存
delete p; // 释放分配的内存

int* arr = new int[5]; // 使用 new[] 分配数组内存
delete[] arr; // 释放分配的数组内存

Note that newmemory allocated using must deletebe freed through the corresponding to avoid memory leaks.

To sum up, newand deleteare dynamic memory allocation and deallocation operators in C++, which are used to allocate and deallocate the memory space required by objects or arrays at runtime.

Chapter 2 Classes and Objects

What are classes?

In object-oriented programming (OOP), a class is a blueprint or template for creating objects. It is an abstract data type used to define the properties (data members) and behavior (member functions) of an object.

A class can be seen as a user-defined data type that encapsulates data and methods for manipulating it. By defining a class, you can create multiple objects of the same type, each with the same properties and behavior. Classes provide a way to organize and manage related data and functionality, making code more readable, maintainable, and extensible.

A class consists of data members and member functions. Data members are variables in the class, which are used to save the state and attributes of the object; member functions are functions in the class, which are used to manipulate and process the data of the object.

A class definition usually includes the class name, declarations of data members and member functions. By instantiating a class (creating an object), you can use the data members and member functions defined in the class to accomplish specific tasks.

To give a simple example, suppose we want to create a class that represents a rectangle, we can define a Rectangleclass named . The class can have data members (such as the width and height of a rectangle) and member functions (such as calculating the area and perimeter of a rectangle). Then, we can create multiple rectangle objects based on this class, and use the methods provided by the class to manipulate and access the properties of these objects.

All in all, class is the core concept in object-oriented programming. It creates reusable code modules by encapsulating data and functions, and realizes the characteristics of code abstraction, encapsulation and inheritance.

object-oriented programming

The object-oriented programming method can better solve the above problems.

Object Oriented Program = Class + Class + ... + Class

The process of designing a program is the process of designing a class.

Object-oriented programming method:

Summarize the common characteristics (attributes) of a certain type of objective things to form a data
structure (multiple variables can be used to describe the properties of things); also sum up the behaviors that such things can perform to form functions, which can be Used to manipulate data structures (this step is called "abstraction"). Then, through a certain grammatical form, the data structure and the function that operates the data structure are "bundled" together to form a "class", so that the data structure and the algorithm that operates the data structure present an obvious close relationship, which is "Encapsulation".

Object-oriented programming has four basic characteristics of "abstract", "encapsulation", "inheritance" and "polymorphism".

classes and objects

In C++, a class (Class) is an object-oriented concept, which describes an abstract entity that contains data and methods (functions), and is used to define the properties and behavior of an object. Classes are simply templates, or blueprints, that are used to declare a new data type with specific properties and capabilities from its definition when an object is created.

An object (Object) is a real thing obtained by instantiating a class (which can be understood as generating a specific instance from the class), and has the attributes and behaviors described by the class. By manipulating the properties and behaviors of objects, we can accomplish various tasks and operations.

For example, we could define a Rectangleclass named Rectangle to describe a rectangle as follows:

class Rectangle 
{
    
    
public:
    double width;
    double height;

    double area()
    {
    
    
        return width * height;
    }
};

This class contains attributes widthand height, which represent the length and width of the rectangle, and defines a member function area()for calculating the area of ​​the rectangle. Now we can create a real rectangle object by instantiating this class like so:

Rectangle r; // 创建一个矩形对象
r.width = 2.5; // 设置矩形的宽度
r.height = 3.7; // 设置矩形的高度
double a = r.area(); // 调用矩形的成员函数计算矩形的面积

Here ris a rectangle object, which contains Rectanglethe attributes and behaviors (member functions) defined in the class. We can perform calculations by directly manipulating these attributes without caring about the specific implementation.

Classes and objects in C++ provide an abstraction and encapsulation mechanism to help programmers better manage and organize code, and program and design in a more efficient and safer manner.

Abstraction, Encapsulation, Polymorphism and Inheritance are the four core concepts of object-oriented programming

Abstraction, Encapsulation, Polymorphism and Inheritance are the four core concepts of object-oriented programming. They help organize and design code, and improve code reusability, maintainability, and extensibility.

  1. Abstraction: Abstraction is the process of reducing complex real-world problems to objects and classes in a program. It focuses on the essential characteristics and behavior of objects, hides unnecessary details, and provides a clear and concise way to describe objects. Abstraction can be achieved through the definition of a class.

  2. Encapsulation: Encapsulation is the mechanism of wrapping data and functions (methods) that process the data in a single unit (class). It achieves information hiding and access control by bundling related data and functions together to form an independent and controllable unit. Only methods defined inside the class can directly access the private member variables of the class, and externally, they can only be accessed through the public interface of the class.

  3. Polymorphism: Polymorphism is the ability to have multiple implementations of the same interface. In polymorphism, you can use the pointer or reference of the base class to refer to the derived class object, and call the corresponding method according to the type of the actual object. Polymorphism allows the same method to have different behaviors, providing a flexible and extensible design method.

  4. Inheritance: Inheritance is a mechanism for deriving new classes from existing classes. The new class (derived class) inherits the properties and methods of the existing class (base class). Through inheritance, derived classes can reuse the code of the base class and extend or modify it on this basis. Inheritance can form a hierarchical structure between classes, which enhances the organization and reusability of code.

These four concepts are interrelated and interact to form the basis of object-oriented programming. Abstraction and encapsulation provide good code design and encapsulation, while polymorphism and inheritance support code flexibility and scalability. By properly applying these concepts, you can create high-quality, maintainable, and extensible object-oriented programs.

When it comes to the concepts of abstraction, encapsulation, polymorphism and inheritance, here is a simple sample code to illustrate the application of these concepts in practice:

#include <iostream>
using namespace std;

// 1. 抽象和封装
class Shape {
    
    
public:
    // 纯虚函数,用于定义接口
    virtual double calculateArea() = 0;
    virtual void display() = 0;
};

// 2. 多态
class Rectangle : public Shape {
    
    
private:
    double length;
    double width;
public:
    Rectangle(double l, double w) : length(l), width(w) {
    
    }

    double calculateArea() override {
    
    
        return length * width;
    }

    void display() override {
    
    
        cout << "Rectangle: Length = " << length << ", Width = " << width << endl;
    }
};

class Circle : public Shape {
    
    
private:
    double radius;
public:
    Circle(double r) : radius(r) {
    
    }

    double calculateArea() override {
    
    
        return 3.14159 * radius * radius;
    }

    void display() override {
    
    
        cout << "Circle: Radius = " << radius << endl;
    }
};

// 3. 继承
class Square : public Rectangle {
    
    
public:
    Square(double s) : Rectangle(s, s) {
    
    }
    
    // 可以覆盖基类的方法
    double calculateArea() override {
    
    
        return Rectangle::calculateArea();
    }

    // 可以使用基类的方法
    void display() override {
    
    
        Rectangle::display();
    }
};

int main() {
    
    
    // 使用抽象类的指针来实现多态
    Shape* shape1 = new Rectangle(5, 3);
    Shape* shape2 = new Circle(2);
    Shape* shape3 = new Square(4);
    
    // 通过多态调用各自的方法
    shape1->display();
    cout << "Area: " << shape1->calculateArea() << endl;

    shape2->display();
    cout << "Area: " << shape2->calculateArea() << endl;

    shape3->display();
    cout << "Area: " << shape3->calculateArea() << endl;

    // 释放内存
    delete shape1;
    delete shape2;
    delete shape3;
    
    return 0;
}

In the above code, we defined an abstract class Shape. ShapeThe class has two pure virtual functions calculateArea()and display(), which have no concrete implementation. Then, we derive two concrete shape classes Rectangleand Circle, which respectively implement Shapethe pure virtual functions of the class and provide their own concrete implementations. At the same time, we also demonstrated the concept of inheritance, created a Squareclass as a Rectanglederived class of the class, and reused Rectanglethe code of the class.

In main()the function, we use Shapethe pointer of the abstract class to achieve polymorphism. Through polymorphism, we can use the pointer of the base class to refer to different derived class objects and call the corresponding method. In this way, we can handle different shape objects through a unified interface.

The sample code demonstrates the main concepts of abstraction, encapsulation, polymorphism, and inheritance, and briefly illustrates their use in practice. Through these concepts, we can better organize and design code and realize the advantages of object-oriented programming.

Exercises after class (2)

2.7 Message is a concept in object-oriented programming, which represents a communication method passed between objects. Messages can be seen as a way for objects to interact. An object can send a message to another object and expect the recipient to perform a corresponding operation.

An event is something that happens or a change in state while the program is running. Events can be user actions, internal state changes of the system, and so on. In object-oriented programming, events are often used to trigger specific actions or notify other objects.

2.9 There are three types of polymorphism: static polymorphism, dynamic polymorphism and parametric polymorphism.

  • Static polymorphism (also known as compile-time polymorphism): implemented through function overloading and operator overloading, the compiler decides which function to call based on function parameters and operator types at compile time.
  • Dynamic polymorphism (also known as run-time polymorphism): through inheritance and virtual functions, the runtime determines which function to call according to the actual type of the object, realizing the characteristics of polymorphism.
  • Parameter polymorphism: Realized by template technology, different function codes are generated according to different template parameters at compile time, improving code flexibility and reusability.

The definitions and implementation mechanisms of these polymorphisms are different, but they can all achieve code flexibility and scalability.

2.12 The object-oriented analysis phase is that part of the software development process whose goal is to understand the requirements in the problem domain and translate them into an object-oriented conceptual model. At this stage, the following work needs to be done:

  • Understand and collect user requirements, and clarify the functions and performance requirements that the system should have.
  • Analyze entities, behaviors, and relationships in the problem domain, identifying potential objects and classes.
  • Define the properties and methods of the object, and establish the preliminary design of the class.
  • Create models such as use case diagrams and class diagrams to describe the functions of the system and the relationships between classes.

2.13 The object-oriented design stage is based on the object-oriented analysis stage, further refines and improves the conceptual model, and carries out the system architecture design. At this stage, the following work needs to be done:

  • According to the requirements analysis results, carry out the detailed design of the class, and determine the details of each class's attributes, methods, and relationships.
  • Design the module structure of the system, and determine the relationship and interface between each module.
  • Determine the architectural style and design pattern of the system, and select appropriate design strategies and techniques.
  • Create models such as class diagrams and sequence diagrams to describe the structure and behavior of the system.

2.14 The object-oriented implementation stage is the stage of transforming the design of the object-oriented design stage into executable code. At this stage, the following work needs to be done:

  • According to the class diagram and sequence diagram in the design stage, write the specific implementation code of the class.
  • Implement relationships and interfaces between classes to ensure that classes work together.
  • Write test code to perform unit tests and integration tests on the implemented classes.
  • Perform performance optimization and debugging to ensure the functional correctness and performance of the system meet the requirements.

2.15 The advantages of object-oriented programming include:

  • Reusability: The object-oriented code structure is more modular and extensible, which can better reuse existing code and reduce repeated development.
  • Flexibility: Object-oriented programming makes the code more flexible and maintainable, and functions can be easily modified and extended.
  • Readability: Use object-oriented design principles and specifications to make the code easier to understand and read, and reduce the complexity of the code.
  • Easy to maintain: Object-oriented programming makes the mapping between the problem domain and the code more closely, and changing a certain part will not affect other parts, which is convenient for program maintenance and iteration.
  • Abstraction and encapsulation: Object-oriented design can encapsulate data and processing operations in objects, and hide internal details through interfaces, enhancing security and code reliability.
  • Polymorphism: The object-oriented programming language supports polymorphism. Through inheritance and virtual function mechanism, the actual type of the object can be determined at runtime, which improves the flexibility and scalability of the code.

Chapter 3 Classes and Objects

Class 4. Classes and Objects

Understanding of classes and objects
C+ is an object-oriented programming language.
To understand C+, you must first understand the two concepts of class (Class)
and object (Object).
Class is an upgrade of structure and a complex data type. Declaration, does not take up memory space,
the object is a variable of this data type, so it takes up memory space

The role and concept of classes:
1. C++ implements encapsulation through classes. Classes are data types defined by users. The
purpose is to make using classes as simple as using basic data types;
2. Three characteristics of object-oriented programming: encapsulation Polymorphism, polymorphism and inheritance,
polymorphism means that functions with different functions can use the same function name, also known as function overloading
3. Data members cannot be initialized in the class body (because no object is defined)
Example : Class A[private:int data:=2;} -> error

insert image description here

operations between objects

Like structure variables, "=" can be used to assign values ​​between objects, but "==", "!=", ">", "<" ">=" "<=" can not be used for comparison, unless these operations The character has been " overloaded ".

Usage 1: object name. member name

CRectangle r1,r2;
r1.w = 5;
r2.Init(5,4); //Init函数作用在 r2 上,即Init函数执行期间访问的
//w 和 h是属于 r2 这个对象的, 执行r2.Init 不会影响到 r1。

Usage 2. Pointer -> member name

CRectangle r1,r2;
CRectangle * p1 = & r1;
CRectangle * p2 = & r2;
p1->w = 5;
p2->Init(5,4); //Init作用在p2指向的对象上

Usage 3: reference name. member name

CRectangle r2;
CRectangle & rr = r2;
rr.w = 5;
rr.Init(5,4); //rr的值变了,r2的值也变
void PrintRectangle(CRectangle & r)
{
    
     cout << r.Area() << ","<< r.Perimeter(); }
CRectangle r3;
r3.Init(5,4); 
PrintRectangle(r3);

Accessibility of class members

In a class definition, use the following access scope keywords to indicate the scope within which class members can be accessed:

private: 私有成员,只能在成员函数内访问
– public : 公有成员,可以在任何地方访问
– protected: 保护成员,以后再说

There is no limit to the number of occurrences and sequence of the above three keywords.

定义一个类
class className {
    
    
private:
私有属性和函数//说明类成员的可访问范围
public:
公有属性和函数//说明类成员的可访问范围
protected:
保护属性和函数//说明类成员的可访问范围
};

If a member is not preceded by the above keywords, it is considered as a private member by default
.

Using Classes and Objects to Realize Addition and Subtraction of Complex Numbers

Addition and subtraction of complex numbers can be implemented by creating a class called Complex. Here is a simple sample code:

class Complex:
    def __init__(self, real, imaginary):
        self.real = real
        self.imaginary = imaginary

    def add(self, other):
        real_part = self.real + other.real
        imag_part = self.imaginary + other.imaginary
        return Complex(real_part, imag_part)

    def subtract(self, other):
        real_part = self.real - other.real
        imag_part = self.imaginary - other.imaginary
        return Complex(real_part, imag_part)

In the above code, we defined a Complex class, which has two attributes: real (real part) and imaginary (imaginary part). Constructors __init__are used to initialize complex objects.

Two methods are also implemented in the class: addand subtract. These two methods are used to implement the addition and subtraction operations of complex numbers, respectively. In these methods, we perform corresponding operations on the real and imaginary parts of the two input complex numbers, and create a new Complex object to represent the result of the operation.

Here is a simple example showing how to use the Complex class:

# 创建两个复数对象
comp1 = Complex(3, 4)
comp2 = Complex(1, 2)

# 相加操作
result_add = comp1.add(comp2)
print("相加结果:", result_add.real, "+", result_add.imaginary, "i")

# 相减操作
result_subtract = comp1.subtract(comp2)
print("相减结果:", result_subtract.real, "+", result_subtract.imaginary, "i")

Running the above code, the output will be:

相加结果: 4 + 6 i
相减结果: 2 + 2 i

In this way, we use classes and objects to implement the addition and subtraction of complex numbers.

constructor

basic concept

a member function

The name is the same as the class name, there can be parameters, but no return value (neither void)

The function is to initialize the object, such as assigning initial values ​​​​to member variables

If no constructor is written when defining a class, the compiler generates a default parameterless constructor

• The default constructor has no parameters and does nothing

If a constructor is defined, the compiler does not generate a default no-argument constructor that is automatically called when the object is created. Once an object is created, it can no longer execute constructors on it A class can have multiple constructors

Why is the constructor needed:

  1. The constructor performs the necessary initialization work. With the constructor, there is no need to write an initialization function, and there is no need to worry about forgetting to call the initialization function.
  2. Sometimes the object is used without being initialized, which will cause a program error.
class Complex {
    
    
private:
double real, imag;
public:
void Set( double r, double i);
}; //编译器自动生成默认构造函数
Complex c1; //默认构造函数被调用
Complex * pc = new Complex; //默认构造函数被调用

class Complex {
    
    
private :
double real, imag;
public:
Complex( double r, double i = 0);
}; 
Complex::Complex( double r, double i) {
    
    
real = r; imag = i;
}
Complex c1; // error, 缺少构造函数的参数
Complex * pc = new Complex; // error, 没有参数
Complex c1(2); // OK
Complex c1(2,4), c2(3,5);
Complex * pc = new Complex(3,4);

可以有多个构造函数,参数个数或类型不同

class Complex {
    
    
private :
double real, imag;
public:
void Set( double r, double i );
Complex(double r, double i );
Complex (double r );
Complex (Complex c1, Complex c2); 
}; 
Complex::Complex(double r, double i)
{
    
    
real = r; imag = i;
}

Complex::Complex(double r)
{
    
    
real = r; imag = 0;
}
Complex::Complex (Complex c1, Complex c2); 
{
    
    
real = c1.real+c2.real;
imag = c1.imag+c2.imag;
}
Complex c1(3) , c2 (1,0), c3(c1,c2);
// c1 = {3, 0}, c2 = {1, 0}, c3 = {4, 0};

构造函数最好是public的,private构造函数

不能直接用来初始化对象

class CSample{
    
    
private:
CSample() {
    
    
}
};
int main(){
    
    
CSample Obj; //err. 唯一构造函数是private
return 0;
}

In C++, a constructor (Constructor) is a special member function that is used to initialize member variables of a class when an object is created. Usually, every class has at least one constructor.

The constructor must have the same name as the class, have no return type (void, int, etc.), and cannot be called manually. The role of the constructor is to assign initial values ​​to member variables when creating an object, as follows:

class Rectangle 
{
    
    
public:
    double width;
    double height;

    // 构造函数
    Rectangle() 
    {
    
    
        width = 0;
        height = 0;
    }
};

The above code defines a Rectangleclass and inside it defines a constructor that initializes the width and height to null values.

The constructor is automatically executed when the object is created, and multiple different constructors can be overloaded according to different needs. For example, use the parameter list to assign values ​​​​to member variables in the constructor:

class Rectangle 
{
    
    
public:
    double width;
    double height;

    // 构造函数 #1
    Rectangle(double w, double h) 
    {
    
    
        width = w;
        height = h;
    }

    // 构造函数 #2
    Rectangle() 
    {
    
    
        width = 0;
        height = 0;
    }
};

Two constructors are defined in the above code. The first constructor is used to pass in the actual width and height for initialization, while the second constructor does not require any parameters, so it is initialized to 0 according to the preset value.

Through the constructor, the member variables can be effectively initialized when the object is created, which improves the efficiency and readability of the code. It should be noted that there can only be one destructor (Destructor) in a class, which is similar to the constructor but starts execution when the object is destroyed.

Using const in c++ to design a complex class of addition, subtraction, multiplication and division

In C++, you can use constkeywords to design a plural class and use constqualifiers for member functions to ensure that the state of the object is not modified. The following is a constsample code that uses to design a complex number class and implement addition, subtraction, multiplication and division operations:

#include <iostream>

class Complex {
    
    
public:
    Complex(double real, double imaginary) : real_(real), imaginary_(imaginary) {
    
    }

    double getReal() const {
    
    
        return real_;
    }

    double getImaginary() const {
    
    
        return imaginary_;
    }

    Complex add(const Complex& other) const {
    
    
        double real_part = real_ + other.getReal();
        double imag_part = imaginary_ + other.getImaginary();
        return Complex(real_part, imag_part);
    }

    Complex subtract(const Complex& other) const {
    
    
        double real_part = real_ - other.getReal();
        double imag_part = imaginary_ - other.getImaginary();
        return Complex(real_part, imag_part);
    }

    Complex multiply(const Complex& other) const {
    
    
        double real_part = real_ * other.getReal() - imaginary_ * other.getImaginary();
        double imag_part = real_ * other.getImaginary() + imaginary_ * other.getReal();
        return Complex(real_part, imag_part);
    }

    Complex divide(const Complex& other) const {
    
    
        double denominator = other.getReal() * other.getReal() + other.getImaginary() * other.getImaginary();
        double real_part = (real_ * other.getReal() + imaginary_ * other.getImaginary()) / denominator;
        double imag_part = (imaginary_ * other.getReal() - real_ * other.getImaginary()) / denominator;
        return Complex(real_part, imag_part);
    }

private:
    double real_;
    double imaginary_;
};

int main() {
    
    
    // 创建两个复数对象
    Complex comp1(3, 4);
    Complex comp2(1, 2);

    // 相加操作
    Complex result_add = comp1.add(comp2);
    std::cout << "相加结果: " << result_add.getReal() << " + " << result_add.getImaginary() << "i" << std::endl;

    // 相减操作
    Complex result_subtract = comp1.subtract(comp2);
    std::cout << "相减结果: " << result_subtract.getReal() << " + " << result_subtract.getImaginary() << "i" << std::endl;

    // 相乘操作
    Complex result_multiply = comp1.multiply(comp2);
    std::cout << "相乘结果: " << result_multiply.getReal() << " + " << result_multiply.getImaginary() << "i" << std::endl;

    // 相除操作
    Complex result_divide = comp1.divide(comp2);
    std::cout << "相除结果: " << result_divide.getReal() << " + " << result_divide.getImaginary() << "i" << std::endl;

    return 0;
}

In the above code, we define a Complex class, which real_and imaginary_private member variables are used to represent the real and imaginary parts of complex numbers.

getReal()And functions are defined in the class getImaginary()to get the real and imaginary part values ​​of complex numbers, and these functions are declared as constto ensure that they do not modify the state of the class.

Then, the class defines add(), subtract(), multiply()and divide()functions that accept a constant reference parameter and return a new Complex object representing the result of the operation.

In the main function, we create two complex number objects and perform addition, subtraction, multiplication and division operations, and then print out the results.

Running the above code, the output will be:

相加结果: 4 + 6i
相减结果: 2 + 2i
相乘结果: -5 + 10i
相除结果: 2.2 + -0.4i

In this way, we use constkeywords to ensure that the member functions of the complex number class do not modify the state of the object, and realize the operations of addition, subtraction, multiplication and division of complex numbers.

functions and arrays

Thinking: 1. How functions use pointers to handle arrays
Answer: The array name in C++ represents the address of the first element of the array
cookies =&cookies[0]
The function call in the above code:
cookies is the name of the array, representing its first element The address of the function, so the function passes the address
Since the array is int type, the parameter type must be an int pointer,
that is, int*, so the function header can also be written as int sum arr(int arr, intn)
only in the function header or function prototype , int
arr is equivalent to int arr[], they both mean that
arr is an int pointer.

2. What does it mean to use an array as a parameter?
In the function call part of the above program, the address of the first element of the cookies array and the number of array elements are
passed to the sum arr() function,
and the next step is the sum arr() function Assign the address of cookies to the arr pointer, and assign Arsizeel
to the int variable n,
that is, the whole program does not pass the content of the array to the function,
but the address of the array, the data type of the element, and the number of elements submitted to the function

3. Pointers and const
There are two ways to use the consti keyword for pointers:
1 is to let the pointer point to a constant object, which can prevent the pointer from being used to modify the pointed value;
2 is to declare the pointer itself as a constant, which can Prevent changing the position pointed to by the pointer
Example: int age=18;
const int *p &age;
/*This statement indicates that p points to a const
int variable,
so p cannot be used to modify this value,
that is, the following two operations cannot be performed : *p+=1;cin>> p; /

Thinking: Is the following operation correct?
*p=30; [Wrong]
age=30; [True]
Assign the address of a regular variable to a const: pointer, [True]
Assign the address of a const variable to a const pointer [True]
Assign the address of a const? variable to a regular Pointer 【wrong】

Classes and Inheritance

insert image description here
insert image description here
insert image description here

insert image description here
insert image description here

Lesson 6. Polymorphism

Compile-time polymorphism: function overloading, operator overloading

Runtime Polymorphism: Virtual Functions

Function overloading and operator overloading

1. Related concepts
C++ allows multiple definitions of a function and operator in the same scope,
which are called function overloading and operator overloading:
an overloaded declaration refers to a function that has been declared in the scope before or methods have declarations with the same name,
but their parameter lists and definitions (implementations) differ.

insert image description here

insert image description here

Exercises after class (3)

#include <iostream>
using namespace std;

class point {
    
    
private:
    int x;
    static int y;

public:
    point(int px = 10) {
    
    
        x = px;
        y++;
    }

    static int getpx(point a) {
    
    
        return (a.x);
    }

    static int getpy() {
    
    
        return (y);
    }

    void setx(int c) {
    
    
        x = c;
    }
};

int point::y = 0;

int main() {
    
    
    point p[5];

    for (int i = 0; i < 5; i++) {
    
    
        p[i].setx(i);
    }

    for (int i = 0; i < 5; i++) {
    
    
        cout << point::getpx(p[i]) << '\t';
        cout << point::getpy() << '\t';
    }

    return 0;
}

This code defines a pointclass named with private xand static member variables y. pointClasses also have constructors, static member functions, and non-static member functions.

Constructor:

  • The constructor takes a default parameter px, which is used to initialize xmember variables.
  • In the constructor, assign pxto xand then increment the static member variable y.

Static member variable y:

  • Static member variables belong to the class itself, not to instances of the class. It shares the same value across all instances of the class.
  • int point::y = 0;The statement defines and initializes static member variables yto 0.

Static member function getpx:

  • getpxIs a static member function that takes an pointobject as a parameter and returns xthe value of the object.
  • In the function body, xits value is obtained by accessing the member variables of the parameter object.

Static member function getpy:

  • getpyIs a static member function that returns ythe value of a static member variable.

Non-static member function setx:

  • setxIs a non-static member function used to set xthe value of a member variable.
  • The function accepts an integer parameter c, which is assigned to xa member variable.

In mainthe function:

  • pointA typed array of length 5 is created p.
  • Use fora loop to sequentially set the value pof each element in the array xto the corresponding subscript value.
  • Using forthe loop again, output the value pof each element in the array xand the value of the static member variable in turn y.
  • The output is tab-delimited.
  • Finally, mainthe function returns 0 and the program ends.

Guess you like

Origin blog.csdn.net/shaozheng0503/article/details/131462616