类的默认函数

六月 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;
}