类的默认函数
六月 06, 2022类的默认函数
在C++中一个类有八个默认函数
默认构造函数; 默认拷贝构造函数; 默认析构函数; 默认重载赋值运算符函数; 默认重载取址运算符函数; 默认重载取址运算符const函数; 默认移动构造函数(C++11); 默认重载移动赋值操作符函数(C++11)。
只是声明一个空类,不做任何事情的话,编译器会自动为你生成一个默认构造函数、一个默认拷贝构造函数、一个默认重载赋值操作符函数和一个默认析构函数。这些函数只有在第一次被调用时,才会被编译器创建,当然这几个生成的默认函数的实现就是什么都不做。所有这些函数都是inline和public的。
我们不希望对象被显示构造(单列模式)或赋值,可以将对应函数声明为private,或者写一个基类,开放部分默认函数,子类去继承就可以了。C++11新增标识符default和delete,控制这些默认函数是否使用。
default:被标识的默认函数将使用类的默认行为,如:A() = default; delete:被标识的默认函数将禁用,如:A() = delete; override:被标识的函数需要强制重写基类虚函数; final:被标识的函数禁止重写基类虚函数;
class A
{
public:
// 默认构造函数;
A();
// 默认拷贝构造函数
A(const A&);
// 默认析构函数
~A();
// 默认重载赋值运算符函数
A& operator = (const A&);
// 默认重载取址运算符函数
A* operator & ();
// 默认重载取址运算符const函数
const A* operator & () const;
// 默认移动构造函数
A(A&&);
// 默认重载移动赋值操作符
A& operator = (const A&&);
};
右值引用的几个思考
#include <tuple>
#include <type_traits>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
using namespace std::string_literals;
using std::cout;
class Foo {
public:
Foo() { cout << "Foo\n"; }
Foo(const Foo& b) { cout << "const Foo&\n"; }
~Foo() { cout << "~Foo\n"; }
Foo& operator=(const Foo& b) {
cout << "operator=\n";
return *this;
}
Foo(Foo&& b) { cout << "Foo&&\n"; }
Foo& operator=(Foo&& b) {
cout << "Foo&&\n";
return *this;
}
};
void bar(Foo&& f) {
}
Foo bar1(Foo&& f) {
return f;
}
Foo& bar2(Foo&& f) {
return f;
}
int main() {
Foo f;
cout << "\n####1\n";
Foo f1(f);
cout << "\n####2\n";
Foo f2 = f;
cout << "\n####3\n";
Foo& f3 = f;
cout << "\n####4\n";
Foo f4;
f4 = f;
cout << "\n####5\n";
Foo f5_;
Foo f5(std::move(f5_));
cout << "\n####6\n";
Foo f6_;
Foo f6 = std::move(f6_); // 在这之后f6_ 就为无效的值了, 已经被移动到f6中了
cout << "\n####7\n";
Foo f7_;
Foo&& f7 = std::move(f7_);// 在这之后f7_ 依然有效, f7是一个引用类型, 和f7_的值一样
// 这里f7 是f7_的右值引用, 不会有复制和移动;右值引用也是引用??!!对比f6
cout << "\n####8\n";
Foo f8_;
bar(std::move(f8_));
cout << "\n####9\n";
Foo f9_;
bar1(std::move(f9_));
cout << "\n####10\n";
Foo f10_;
bar2(std::move(f10_));
return 0;
}