=default在类无阻碍因素(如const/引用成员、自定义构造函数)时才生效;否则需类外定义或手动初始化;显式声明移动函数会隐式删除拷贝函数,须主动=default恢复。

什么时候=default才真正生效
它不是“写了就管用”的语法糖。编译器是否真能为你生成默认构造函数或拷贝函数,取决于类的成员和已有定义。常见失效场景包括:
- 类中已有其他构造函数(比如
A(int)),且没写=default在定义处 - 类含
const成员或引用成员(如int& ref;),它们无法被默认初始化,编译器直接拒绝合成 -
=default只写在类内声明里(如A() = default;),但类外没提供定义——这在有阻碍因素时是无效的 - 基类或某个成员的默认构造/拷贝函数被
=delete了,那派生类也无法合成
默认构造函数:类内声明 vs 类外定义
若类干净(无const/引用成员、无自定义构造函数),可直接在类内声明=default:
class A {
public:
A() = default; // ✅ 合法:无阻碍,编译器立刻生成
A(int x) : val(x) {}
private:
int val;
};
但一旦有const成员,就必须移到类外定义,并确保该成员有默认初始化器(C++11起支持):
class B {
public:
B() = default; // ❌ 编译失败:const_ref 未初始化
// 正确写法:
// B() : const_ref(i) {} // 手动初始化(非 default 语义)
private:
const int& const_ref;
int i;
};
<p>// 或者:类外定义 + 成员默认初始化
class C {
public:
C() = default; // ✅ 声明即可,因成员已带默认值
private:
const int x = 42; // C++11 起允许
int& ref = i; // 引用必须绑定到生存期足够的对象
int i;
};
C::C() = default; // ✅ 类外定义,满足所有约束</p>
拷贝构造与拷贝赋值:显式启用的典型场景
当你自己写了析构函数或移动操作,编译器会自动禁用默认拷贝函数(防止浅拷贝引发资源重复释放)。此时=default是唯一恢复方式:
- 必须写在定义处(类内或类外均可,但类内更常见)
- 要确保所有成员支持拷贝(比如没有被
=delete的拷贝构造) - 如果类管理资源(如裸指针),
=default仍只做浅拷贝——这不是 bug,而是你明确选择不干预
class D {
public:
~D() { delete ptr; } // 自定义析构 → 编译器不再合成拷贝函数
D(const D&) = default; // ✅ 显式启用:逐成员拷贝
D& operator=(const D&) = default; // ✅ 同理
private:
int* ptr = new int(0);
};
容易被忽略的陷阱:移动函数会“传染”禁用拷贝
只要显式声明了移动构造或移动赋值(哪怕用=default),编译器就自动把拷贝构造和拷贝赋值标记为deleted——除非你主动用=default恢复它们:
class E {
public:
E(E&&) = default; // ❌ 此时 E(const E&) 和 operator= 都隐式 deleted
E(const E&) = default; // ✅ 必须补上,否则 E e1, e2; e2 = e1; 报错
E& operator=(const E&) = default;
};
这个规则常导致“加了一行=default,结果一堆拷贝调用突然编译不过”的问题。真正关键的不是“怎么写”,而是“写完之后,其他五个函数还剩几个活着”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











