2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Table of contents
4. Default member functions of a class
Class definition format
class is the keyword for defining a class, Stack is the name of the class, and {} is the body of the class. Note that the semicolon at the end of the definition is not omitted. The content in the class body is called the members of the class: the variables in the class are called the attributes or member variables of the class; the functions in the class are called the methods or member functions of the class.
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
- //成员变量
- int* a;
- int top;
- int capacity;
- //成员函数
- void Push()
- {
-
- }
- void Pop()
- {
-
- }
- };//分号不能省略
- int main()
- {
-
-
- return 0;
- }
- //为区分成员变量,一般前面加_
- //成员变量
- int* _a;
- int _top;
- int _capacity;
A way to implement encapsulation in C++, using classes to combine the properties and methods of an object to make the object more complete, and selectively provide its interface to external users through access permissions.
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
-
- ///
-
- void Push()
- {
-
- }
- //Push 没给限定符 class默认私有 private
- ///
- public:
- void Pop()
- {
-
- }
- int Swap()
- {
-
- }
- //Pop和Swap 被public修饰,直到下一个限定符出现之前都为公有
- ///
- protected:
- int add();
- //add 被public修饰,直到下一个限定符出现之前都为保护
- /// /
-
- private:
-
- int* _a;
- int _top;
- int _capacity;
- //成员变量被private修饰,直到}结束都为私有
- };
- int main()
- {
- Stack st;
- //公有可以访问
- st.Pop();
- st.Swap();
- //私有不可访问
- st._top;
-
-
-
- return 0;
- }
Additional Note:
A class defines a new scope. All members of the class are in the scope of the class. When defining members outside the class, you need to use the :: scope operator to indicate which class scope the member belongs to.
The class scope affects the search rules of the compiler. In the following program, if the class scope Stack is not specified for Init, the compiler will treat Init as a global function. If it cannot find members such as _top during compilation, it will look for them in the class scope.
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
-
- public:
- void Init(int x, int y);
-
- };
- void Stack::Init(int x, int y)
-
- {
- _top = x;
- _capacity = y;
- }
- int main()
- {
-
- return 0;
- }
Notice:
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
- //声明
-
- int* _a;
- int _top;
- int _capacity;
-
- };
-
- int main()
- {
-
- Stack::_top = 2024;
- //编译器报错,_top只是声明,并未实例化
-
- return 0;
- }
-
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Stack
- {
-
-
- //声明
- int* _a;
- int _top;
- int _capacity;
-
- };
-
- int main()
- {
-
-
- Stack st;
- st._top=2024;
- //Stack实例化出st,系统已经给st分配内存了,可以存储数据,编译通过
-
- return 0;
- }
-
-
Memory alignment rules
- class A
- {
- public:
- void Print()
- {
- cout << _ch << endl;
- }
- private:
- char _ch;
-
- int _i;
- };
- //_ch 是一个字节,默认对齐数是4,最大对齐数是4,所以开辟4个字节用来存在_ch
- // _i是4个字节,默认对齐数是4,最大对齐数是4,所以开辟4个字节用来存储_i
- class B
- {
- public:
- void Print()
- {
- //。。。
- }
-
-
- };
- class B
- {
-
-
- };
- //B和C里面没有存储任何成员变量,只有一个函数,可成员函数不存对象里面
- // 按理来说是0,但是结构体怎么会没大小,为表示对象存在C++对这种规定大小为1,为了占位标识对象存在
After the compiler compiles, the member functions of the class will add a pointer to the current class in the first position of the formal parameter by default, called the this pointer
For example, the prototype of Init in the Date class is void Init (Date * const this, int year, int month, int day). The member variables in the member functions of the class are accessed through the this pointer. For example, in the Init function, _year is assigned a value, this->_year=year
prototype:
- class Date
- {
- void Print()
- {
-
- cout << _year << "n" << _month << "n" << _day << endl;
- }
- void Init( int year, int month,int day)
- {
- _year = year;
- _month = month;
- _day = day;
-
- }
-
- private:
- int _year;
- int _month;
- int _day;
-
- };
-
- Date d1;
- d1.Init(2024,7,10);
-
- d1.Print();
- Date d2;
-
- d2.Init(2024, 7, 9);
- d2.Print();
-
Real prototype
- class Date
- {
- void Init(Date* const this,int year, int month,int day)
-
- {
- this->_year = year;
- this->_month = month;
- this->_day = day;
-
- }
- void Printf(Date* const this)
-
- {
-
- cout << this->_year << "n" <<this-> _month << "n" << this->_day << endl;
- }
- private:
- int _year;
- int _month;
- int _day;
-
- };
- Date d1;
- d1.Init(&d1,2024,7,10);
- d1.Print(&d1);
-
- Date d2;
- d2.Init(&d2,2024, 7, 9);
- d2.Print();
C++ stipulates that it is not allowed to write this pointer in the position of actual parameters and formal parameters (the compiler will handle it during compilation), but you can use this pointer explicitly in the function body. This pointer cannot be modified, but the content pointed to by this pointer can be modified.
This pointer is stored in the stack
The default member function is a member function that is automatically generated by the compiler without explicit definition by the user.
The constructor is a special member function. It should be noted that although the name of the constructor is a constructor, the main content of the constructor is not to create space for objects (the local objects we usually use are created when the stack frame is created, and the space is already created), but to initialize the object when the object is instantiated. The essence of the constructor is to replace the function of the Init function we wrote in the Stack and Date classes before. The automatic call feature of the constructor perfectly replaces the Init function.
Features of the constructor:
- class Date
- {public:
- //1.无参构造函数
- Date()
- {
- _year = 1;
- _month = 1;
- _day = 1;
- }
- //2.带参构造函数
- Date(int year, int month, int day)
- {
- _year = year;
- _month = month;
- _day = day;
- }
-
-
- //3.全缺省构造函数
- Date(int year = 1, int month = 1, int day = 1)
- {
- _year = year;
- _month = month;
- _day = day;
- }
- private:
- int _year;
- int _month;
- int _day;
-
- };
The no-parameter constructor, the full default constructor, and the constructor generated by the compiler by default when we do not write a constructor are all called default constructors. However, only one of these three can exist, and they cannot exist at the same time. Although the no-parameter constructor and the full default constructor constitute function overloading, there will be ambiguity when calling. Note that the default constructor is not the only constructor generated by the compiler by default. The no-parameter constructor and the full default constructor are also default constructors. In summary, they can be called without passing parameters.
If we don't write it, the compiler generates the structure by default, which has no requirements for the initialization of member variables of built-in types. In other words, whether to initialize is uncertain and depends on the compiler.
- //text.cpp
- #include<iostream>
- using namespace std;
- typedef int STDataType;
- class Stack
- {
- public:
- Stack(int n = 4)
- {
- _a = (STDataType*)malloc(sizeof(STDataType) * n);
- if (nullptr == _a)
- {
- perror("malloc申请失败");
- }
- _capacity = n;
- _top = 0;
- }
-
- private:
- STDataType* _a;
- size_t _capacity;
- size_t _top;
- };
- //两个Stack实现队列
- class MyQueue
- {
- private:
- int size;
- Stack pushst;
- Stack popst;
- };
-
- int main()
- {
-
- MyQueue my;
-
-
- return 0;
- }
-
C++ divides types into custom types and built-in types (basic types). Built-in types are native data types provided by the language, such as int/char/double/pointer, etc. Custom types are types that we define ourselves using keywords such as class/struct. The constructor is automatically initialized here, and VS also initializes the built-in type size. Different compilers have different initialization values, and C++ does not specify
For custom type member variables, it is required to call the default constructor of this member variable for initialization. If this member variable does not have a default constructor, an error will be reported. To initialize this member variable, an initialization list is required to solve it.
Summary: In most cases, we need to implement the constructor ourselves. In a few cases like MyQueue and Stack has a default constructor, MyQueue can be automatically generated and used.
- ~Stack()
- {
- free(_a);
- _a = nullptr;
- _top = _capacity = 0;
- }
Characteristics of destructor:
1. The destructor name is the character ~ added before the class name
2. No parameters and no return value (same as the constructor)
3. A class can only have one destructor. If it is not explicitly defined, the system will automatically generate a default destructor.
4. When the object declaration cycle ends, the system automatically calls the destructor.
5. Similar to the constructor, we do not write the destructor automatically generated by the compiler. We do not process the built-in type members. Custom type members will call other destructors.
6. It should also be noted that when we display the destructor, the destructor of the custom type member will also be called, that is, the destructor of the custom type member will be automatically called no matter what the situation.
- //text.cpp
- #include<iostream>
- using namespace std;
- typedef int STDataType;
- class Stack
- {
- public:
- Stack(int n = 4)
- {
- _a = (STDataType*)malloc(sizeof(STDataType) * n);
- if (nullptr == _a)
- {
- perror("malloc申请失败");
- }
- _capacity = n;
- _top = 0;
-
-
- }
-
- ~Stack()
- {
- free(_a);
- _a = nullptr;
- _top=_capacity=0;
- }
- private:
- STDataType* _a;
- size_t _capacity;
- size_t _top;
-
- };
- //两个Stack实现队列
- class MyQueue
- {public:
- //编译器默认生成MyQueue的构造函数调用了Stack的构造,完成了两个成员的初始化
- //编译器默认生成MyQueue的析构函数调用了Stack的析构,释放了Stack内部的资源
- //显示写析构也会调用Stack的析构
- ~MyQueue()
- {
- cout << "~MyQueue" << endl;
- }
- private:
-
- Stack pushst;
- Stack popst;
-
- };
-
-
- int main()
- {
-
- MyQueue my;
-
-
- return 0;
- }
The destructor in MyQueue does nothing, but C++ requires calling other destructors to release memory.
If there is no resource application, the destructor can be omitted and the default destructor generated by the compiler can be used directly, such as Date. If the default generated destructor can be used, there is no need to explicitly write the destructor, such as MyQueue. However, when there is a resource application, the destructor must be written directly, otherwise it will cause resource leakage, such as Stack
-
-
- bool operator<(Date d1, Date d2)
- {
-
- }
- bool operator==(Date d1,Date d2)
- {
- return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
- }
- //text.cpp
- #include<iostream>
- using namespace std;
-
- class Date
- {
- public:
- Date(int year, int month, int day)
- {
- _year= year;
- _month = month;
- _day = day;
-
- }
-
-
-
- int _year;
- int _month;
- int _day;
-
- };
-
- bool operator<(Date d1, Date d2)
- {
-
- }
- bool operator==(Date d1,Date d2)
- {
- return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
- }
- int main()
- {
-
- Date d1(2024, 7, 10);
- Date d2(2024,7,9);
- //两种用法都可以
- d1 == d2;
- operator==(d1 , d2);
- return 0;
- }