Table of contents
1. final and override keywords
Second, the new function of the class
2.2 Class member variable initialization
Note: All test codes in the C++ column are compiled and run in the environment of vs2019
1. final and override keywords
These two keywords are used for inheritance and polymorphism
1.1 final
final: Modifies the virtual function, indicating that the virtual function can no longer be rewritten
test code
//基类
class Person {
public:
//被final修饰,该虚函数不能再被重写
virtual void BuyTicket() final
{
cout << "Person-买票-全价" << endl;
}
};
//派生类
class Student : public Person {
public:
//派生类的虚函数重写了父类的虚函数
virtual void BuyTicket() { cout << "Student-买票-半价" << endl; }
};
compile directly error
The final keyword can also be used to implement a class that cannot be inherited
How to implement a class that cannot be inherited? ?
- Make the constructor private, which is the practice of C++98
- Add the final keyword when defining a class, which is the practice of C++11
test code
//基类使用 final 修饰
class A final
{};
//派生类无法进行继承基类
class B : public A
{};
compile directly error
1.2 override
override: Check whether the virtual function of the derived class overrides a virtual function of the base class, if not, compile and report an error
test code
//基类
class Person {
public:
//基类的虚函数
virtual void BuyTicket() { cout << "Person-买票-全价" << endl; }
};
//派生类
class Student : public Person {
public:
//派生类完成了虚函数的重写,编译通过
virtual void BuyTicket()override
{
cout << "Student-买票-半价" << endl;
}
};
//派生类
class Soldier : public Person
{
public:
//派生类没有完成虚函数的重写,编译报错
virtual void BuyTicket(int n)override
{
cout << "Soldier-优先-买票" << endl;
}
};
compile directly error
Second, the new function of the class
2.1 Default member functions
Before C++11, a class had the following six default member functions
- 1. Constructor
- 2. Destructor
- 3. Copy constructor
- 4. Copy assignment overloading
- 5. Take address overload
- 6. const address overloading
Last but not least are the first 4, the last two are of little use. The default member function is that if we don't write the compiler will generate a default
C++11 adds two new ones: move constructor and move assignment operator overloading
Build Conditions for Default Move Constructs
If you do not implement the move constructor yourself, and do not implement any of the destructor, copy construction, and copy assignment overloads. then the compiler will automatically generate a default move construct.
Default behavior for move construction:
- The move constructor generated by default will execute member-by-member byte-by-byte copy for built-in type members. For custom type members, you need to check whether the member implements move construction. If it is implemented, call move construction. If not, call copy construction
Generate condition for default move assignment
If you do not implement the move assignment overload function yourself, and do not implement any of the destructor, copy construction, and copy assignment overloads, then the compiler will automatically generate a default move assignment.
Default behavior for move assignment:
The move constructor generated by default will execute member-by-member byte-by-byte copy for built-in type members. For custom type members, you need to check whether the member implements move
assignment . (The default move assignment is exactly similar to the move construction above)
Note : If move construction or move assignment is provided, the compiler will not automatically provide copy construction and copy assignment
The test code needs to use a simplified version of the string implemented by the mock
namespace fy
{
class string
{
public:
//构造函数
string(const char* str = "")
{
_size = strlen(str);//字符串大小
_capacity = _size;//构造时,容量大小默认与字符串大小相同
_str = new char[_capacity + 1];//为字符串开辟空间(多开一个用于存放'\0')
strcpy(_str, str);//将C字符串拷贝到已开好的空间
}
//拷贝构造 -- 现代写法
string(const string& s)
:_str(nullptr)
, _size(0)
,_capacity(0)
{
cout << "string(const string& s) -- 深拷贝" << endl;
string tmp(s._str);//复用构造函数,构造 tmp对象
swap(tmp);//交换
}
//赋值重载 -- 现代写法1
string& operator=(const string& s)
{
cout << "string& operator=(const string& s) -- 深拷贝" << endl;
if (this == &s)//检查自我赋值
{
return *this;
}
string tmp(s);//复用拷贝构造函数,用s拷贝构造出对象tmp
swap(tmp);
return *this;//返回左值,目的是为了支持连续赋值
}
// 移动构造
string(string&& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
cout << "string(string&& s) -- 移动语义" << endl;//更明显观察是否调用了该函数
swap(s);//与右值的资源进行直接交换,不进行深拷贝
}
// 移动赋值
string& operator=(string&& s)
{
cout << "string& operator=(string&& s) -- 移动语义" << endl;//使更明显观察是否调用了该函数
swap(s);//与右值的资源进行直接交换,不进行深拷贝
return *this;//支持连续赋值
}
//析构函数
~string()
{
delete[] _str; //释放_str指向的空间
_str = nullptr;
_size = _capacity = 0;
}
//交换两个字符串
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
private:
char* _str;
size_t _size;
size_t _capacity;
};
}
Then write a simple Person class that uses the string we simulated
class Person
{
public:
//构造函数
Person(const char* name = "", int age = 0)
:_name(name)
, _age(age)
{}
private:
fy::string _name;
int _age;
};
int main()
{
Person s1;
Person s2 = s1;
Person s3 = std::move(s1);
Person s4;
s4 = std::move(s2);
return 0;
}
Note: The Person class here does not implement copy construction, assignment overloading, and destructors, but only implements constructors, which meet the generation conditions of move assignment and move copy functions
The result of the operation is as follows
The default generated move construction and move assignment functions will perform member-by-member byte-by-byte copy for built-in type members. For custom type members, you need to check whether the member implements move
assignment Call copy assignment, which is fully consistent with
Test below
Once any one or more of the copy construction, copy assignment and destructor functions of the Person class are implemented, and the generation conditions of the move assignment and move copy functions are not satisfied, the move assignment and move copy functions will not be generated
test code
class Person
{
public:
//构造函数
Person(const char* name = "", int age = 0)
:_name(name)
, _age(age)
{}
拷贝构造
//Person(const Person& p)
// :_name(p._name)
// ,_age(p._age)
//{}
赋值重载
//Person& operator=(const Person& p)
//{
// if(this != &p)
// {
// _name = p._name;
// _age = p._age;
// }
// return *this;
//}
//析构函数
~Person()
{}
private:
fy::string _name;
int _age;
};
int main()
{
Person s1;
Person s2 = s1;
Person s3 = std::move(s1);
Person s4;
s4 = std::move(s2);
return 0;
}
operation result
Since the default move assignment and move copy functions are not generated, the Person class can only call the deep copy function of string at this time, and the move assignment and move constructor cannot be called.
2.2 Class member variable initialization
C++11 allows initial default values for member variables when defining a class. The default generated constructor will be initialized with these default values . It has been discussed in the chapter on classes and objects.
class Person
{
public:
//...
private:
//非静态成员变量,可以在成员声明时给缺省值
string _name = "张三"; //缺省值
int _age = 22; //缺省值
static int _n; //静态成员变量不能给缺省值
};
Note: This is not initialization, the value given is the default value
2.3 default keyword
The role of the default keyword is: to force the generation of default functions
C++11 gives you more control over which default functions to use. Suppose you want to use some default function, but for some reason this function is not generated by default. For example: if we provide a copy structure, the move structure will not be generated, then we can use the default keyword to display the generation of the specified move structure
Use: Add =default after the declaration that needs to be forced to generate a default function
test code
class Person
{
public:
//构造函数
Person(const char* name = "", int age = 0)
:_name(name)
, _age(age)
{}
//拷贝构造
Person(const Person& p)
:_name(p._name)
,_age(p._age)
{}
//移动构造
Person(Person&& p) = default;
private:
fy::string _name;
int _age;
};
int main()
{
Person s1;
Person s2 = s1;
Person s3 = std::move(s1);
return 0;
}
As a result of the operation, the default move construction can be generated after using the default keyword, even if the copy constructor is implemented
2.4 delete keyword
The role of the delete keyword is: to prohibit the generation of default functions
Use: Add =delete after the statement that needs to prohibit the generation of default functions
If you want to limit the generation of certain default functions:
- In C++98, the function is set to private, and only declared without definition, so that an error will be reported as long as others want to call it.
- It is simpler in C++11, just add =delete to the function declaration, this syntax instructs the compiler not to generate a default version of the corresponding function, and the function modified by =delete is called delete
Test code:
To prevent a class from being copied, you can use =delete to modify the copy construction and assignment of the class
class A
{
public:
A()
{}
private:
//强制不允许生成
A(const A&) = delete;
A& operator=(const A&) = delete;
};
int main()
{
A a1;
A a2(a1);
return 0;
}
compile error
----------------I am the dividing line---------------
The article is over here, the next one will be updated soon