构造函数是对象创建时自动且仅执行一次的强制入口,负责初始化const成员、引用成员及无默认构造函数的自定义类型成员,必须用初始化列表;普通init()函数需手动调用,易遗漏导致未定义状态。

构造函数是对象诞生时的强制入口,普通函数不是
构造函数在 new 或栈上定义对象时**自动调用**,且仅在此刻执行一次;而普通初始化函数(比如叫 init())必须手动调用,调用时机、次数、甚至是否调用都由程序员控制。这意味着:如果忘了调用 init(),对象可能处于未定义状态;但只要对象被成功创建,构造函数就一定已执行完毕。
const 成员和引用成员只能靠构造函数(且必须用初始化列表)初始化
普通函数体内对 const 成员赋值会直接编译失败,例如:
class Bad {
const int x;
public:
Bad() { x = 10; } // ❌ 错误:不能给 const 成员赋值
};
同样,引用成员也必须在定义时绑定,无法“之后再赋值”。只有构造函数的初始化列表能完成这类初始化:
-
const成员:必须出现在初始化列表中,如:x(10) - 引用成员:如
int& ref,必须绑定到一个已存在的变量,也只能在初始化列表里写:ref(other_var) - 没有默认构造函数的自定义类型成员(如
std::vector<int></int>本身有默认构造,但你自己写的MyBuffer若只提供MyBuffer(size_t)),也必须在初始化列表中显式调用带参构造
构造函数体内的“赋值”其实是二次操作,效率更低
对于非内置类型(比如 std::string、std::vector),在构造函数体内写 str = "hello",实际发生的是:
- 先调用默认构造函数初始化
str(空字符串) - 再调用
operator=执行赋值(可能触发内存分配、拷贝等)
而用初始化列表 :str("hello") 是一步到位:直接调用 std::string 的带参构造,跳过默认构造+赋值两步。这对性能敏感或资源管理类尤其关键。
构造函数支持重载和隐式类型转换,普通函数不自动参与对象构建流程
你可以写多个构造函数(如 Person()、Person(const char*)、Person(const Person&)),编译器根据参数自动选择;还能配合 explicit 控制隐式转换。而普通初始化函数只是普通成员函数,不会被编译器用于对象创建上下文——比如你不能写 Person p = "Alice" 去触发 init(const char*),这行不通。
真正容易被忽略的是:初始化顺序由类内成员声明顺序决定,跟初始化列表里写的先后无关;而普通函数里的赋值顺序完全按代码顺序来——这点一旦混用,很容易引发未定义行为。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











