一、构造函数的基本分类
1.1 默认构造函数(Default Constructor)
没有参数或所有参数都有默认值的构造函数。
class MyClass {
public:
// 1. 显式默认构造函数
MyClass() {
data = 0;
name = "default";
std::cout << "Default constructor called\n";
}
// 2. 编译器生成的隐式默认构造函数
// 如果没有任何构造函数,编译器会自动生成
private:
int data;
std::string name;
};
// 使用
MyClass obj1; // 调用默认构造函数
MyClass obj2{}; // C++11 统一初始化
MyClass* obj3 = new MyClass(); // 动态分配
1.2 参数化构造函数(Parameterized Constructor)
带有参数的构造函数。
class Point {
private:
double x, y;
public:
// 参数化构造函数
Point(double xVal, double yVal) {
x = xVal;
y = yVal;
std::cout << "Parameterized constructor: (" << x << ", " << y << ")\n";
}
// 带默认值的参数化构造函数
Point(double xVal = 0.0, double yVal = 0.0, double zVal = 0.0) {
x = xVal;
y = yVal;
std::cout << "Constructor with defaults called\n";
}
};
// 使用
Point p1(10.5, 20.3); // 调用参数化构造函数
Point p2(15.0); // 使用默认值
Point p3{}; // 全部使用默认值
1.3 拷贝构造函数(Copy Constructor)
用同类型的另一个对象初始化新对象。
class String {
private:
char* buffer;
size_t length;
public:
// 普通构造函数
String(const char* str) {
length = strlen(str);
buffer = new char[length + 1];
strcpy(buffer, str);
std::cout << "Regular constructor: " << buffer << "\n";
}
// 拷贝构造函数(深拷贝)先申请一个新的内存空间
String(const String& other) {
length = other.length;
buffer = new char[length + 1];
strcpy(buffer, other.buffer);
std::cout << "Copy constructor: " << buffer << "\n";
}
// 拷贝构造函数(浅拷贝 - 通常不要这样做)
// String(const String& other) : buffer(other.buffer), length(other.length) {}
~String() {
delete[] buffer;
}
void print() const {
std::cout << "String: " << (buffer ? buffer : "null") << "\n";
}
};
// 使用拷贝构造函数的场景
void demonstrateCopyConstructor() {
String s1("Hello"); // 普通构造函数
// 场景1:直接初始化
String s2(s1); // 拷贝构造函数
String s3 = s1; // 拷贝构造函数(不是赋值!)
// 场景2:传参
void processString(String str); // 值传递会调用拷贝构造函数
processString(s1);
// 场景3:返回值
String createString() {
String temp("Temp");
return temp; // 可能调用拷贝构造函数(NRVO优化可能避免)
}
}
1.4 移动构造函数(Move Constructor)(C++11)
将资源从一个临时对象转移到新对象。
class DynamicArray {
private:
int* data;
size_t size;
public:
// 普通构造函数
DynamicArray(size_t n) : size(n), data(new int[n]) {
std::fill(data, data + size, 0);
std::cout << "Regular constructor, size: " << size << "\n";
}
// 拷贝构造函数
DynamicArray(const DynamicArray& other) : size(other.size), data(new int[other.size]) {
std::copy(other.data, other.data + size, data);
std::cout << "Copy constructor, size: " << size << "\n";
}
// 移动构造函数(C++11)
DynamicArray(DynamicArray&& other) noexcept
: data(other.data), size(other.size) { // 窃取资源
other.data = nullptr; // 置空原对象
other.size = 0;
std::cout << "Move constructor, size: " << size << "\n";
}
~DynamicArray() {
delete[] data;
}
// 移动赋值运算符(通常与移动构造函数一起实现)
DynamicArray& operator=(DynamicArray&& other) noexcept {
if (this != &other) {
delete[] data; // 释放现有资源
data = other.data; // 窃取资源
size = other.size;
other.data = nullptr;
other.size = 0;
}
return *this;
}
};
// 使用移动构造函数
void demonstrateMoveConstructor() {
DynamicArray arr1(100); // 普通构造函数
// 场景1:从临时对象移动
DynamicArray arr2(std::move(arr1)); // 显式移动
// 场景2:从函数返回值移动
auto createArray = []() -> DynamicArray {
DynamicArray temp(50);
// ... 操作 temp
return temp; // 可能调用移动构造函数
};
DynamicArray arr3 = createArray(); // 移动构造
// 场景3:标准库容器中的移动
std::vector<DynamicArray> arrays;
arrays.push_back(DynamicArray(30)); // 移动构造
arrays.emplace_back(40); // 原地构造,无移动
}
1.5 委托构造函数(Delegating Constructor)(C++11)
一个构造函数调用同类的另一个构造函数。
class Employee {
private:
std::string name;
int id;
double salary;
std::string department;
public:
// 主构造函数(包含所有参数)
Employee(const std::string& n, int i, double s, const std::string& d)
: name(n), id(i), salary(s), department(d) {
std::cout << "Main constructor called\n";
validateData();
}
// 委托构造函数:委托给主构造函数
Employee(const std::string& n, int i, double s)
: Employee(n, i, s, "Unassigned") { // 委托调用
std::cout << "Delegating constructor (3 params)\n";
}
// 另一个委托构造函数
Employee(const std::string& n, int i)
: Employee(n, i, 0.0, "Unassigned") { // 委托调用
std::cout << "Delegating constructor (2 params)\n";
}
// 默认构造函数也委托
Employee() : Employee("Unknown", 0, 0.0, "Unassigned") {
std::cout << "Default delegating constructor\n";
}
private:
void validateData() {
if (salary < 0) throw std::invalid_argument("Salary cannot be negative");
if (id < 0) throw std::invalid_argument("ID cannot be negative");
}
};
// 使用
Employee e1; // 调用默认委托构造函数
Employee e2("Alice", 1001); // 调用2参数委托构造函数
Employee e3("Bob", 1002, 50000.0); // 调用3参数委托构造函数
Employee e4("Charlie", 1003, 60000.0, "Engineering"); // 调用主构造函数
1.6 继承构造函数(Inheriting Constructor)(C++11)
派生类继承基类的构造函数。
class Base {
protected:
int baseValue;
public:
Base() : baseValue(0) {
std::cout << "Base default constructor\n";
}
Base(int val) : baseValue(val) {
std::cout << "Base parameterized constructor: " << val << "\n";
}
Base(int val1, int val2) : baseValue(val1 + val2) {
std::cout << "Base two-parameter constructor\n";
}
};
class Derived : public Base {
private:
int derivedValue;
std::string name;
public:
// C++11之前:需要手动重写所有基类构造函数
/*
Derived() : Base(), derivedValue(0), name("") {}
Derived(int val) : Base(val), derivedValue(0), name("") {}
Derived(int val1, int val2) : Base(val1, val2), derivedValue(0), name("") {}
*/
// C++11:使用继承构造函数
using Base::Base; // 继承Base的所有构造函数
// 可以添加额外的初始化
Derived() : Base(), derivedValue(0), name("DerivedDefault") {
std::cout << "Derived default constructor\n";
}
// 也可以定义新的构造函数
Derived(const std::string& n) : Base(), derivedValue(0), name(n) {
std::cout << "Derived string constructor: " << name << "\n";
}
void print() const {
std::cout << "Base: " << baseValue
<< ", Derived: " << derivedValue
<< ", Name: " << name << "\n";
}
};
// 使用
Derived d1; // 调用Derived默认构造函数
Derived d2(42); // 调用继承的Base(int)构造函数
Derived d3(10, 20); // 调用继承的Base(int, int)构造函数
Derived d4("Custom"); // 调用新的字符串构造函数
1.7 显式构造函数(Explicit Constructor)
防止隐式类型转换。
class SmartPointer {
private:
int* ptr;
public:
// 显式构造函数 - 禁止隐式转换
explicit SmartPointer(int* p = nullptr) : ptr(p) {
std::cout << "Explicit constructor\n";
}
// 非显式构造函数 - 允许隐式转换
SmartPointer(int value) : ptr(new int(value)) {
std::cout << "Non-explicit constructor\n";
}
~SmartPointer() {
delete ptr;
}
int* get() const { return ptr; }
};
class Container {
private:
SmartPointer sp;
public:
// 接受SmartPointer参数的构造函数
explicit Container(const SmartPointer& s) : sp(s) {}
// 接受int指针的构造函数
Container(int* p) : sp(p) {} // 这里会调用SmartPointer的构造函数
};
void demonstrateExplicit() {
int* rawPtr = new int(42);
// 正常使用
SmartPointer sp1(rawPtr); // OK:直接初始化
SmartPointer sp2 = SmartPointer(rawPtr); // OK:显式转换
// 隐式转换(被explicit阻止)
// SmartPointer sp3 = rawPtr; // ❌ 错误:不能隐式转换
Container c1(sp1); // OK:传递SmartPointer对象
Container c2(rawPtr); // OK:调用Container(int*)构造函数
// 隐式转换到SmartPointer再构造Container
// Container c3 = rawPtr; // ❌ 错误:需要两次隐式转换
}
二、特殊用途构造函数
2.1 转换构造函数(Conversion Constructor)
允许从其他类型隐式转换的构造函数。
class Complex {
private:
double real, imag;
public:
// 转换构造函数:从double到Complex
Complex(double r, double i = 0.0) : real(r), imag(i) {
std::cout << "Conversion constructor: " << r << " + " << i << "i\n";
}
// 转换构造函数:从std::string到Complex
Complex(const std::string& str) {
// 解析字符串如 "3.14+2.71i"
size_t plusPos = str.find('+');
size_t iPos = str.find('i');
if (plusPos != std::string::npos && iPos != std::string::npos) {
real = std::stod(str.substr(0, plusPos));
imag = std::stod(str.substr(plusPos + 1, iPos - plusPos - 1));
} else {
real = std::stod(str);
imag = 0.0;
}
std::cout << "String conversion constructor: " << str << "\n";
}
void display() const {
std::cout << real << " + " << imag << "i\n";
}
// 类型转换运算符(与转换构造函数配对)
explicit operator double() const {
return real; // 只返回实部
}
};
void demonstrateConversion() {
Complex c1(3.14); // OK:调用转换构造函数
Complex c2 = 2.71; // OK:隐式转换(没有explicit)
// 多个参数的转换
Complex c3 = 1.0; // imag默认为0
Complex c4 = Complex(1.0, 2.0); // 显式调用
// 字符串转换
Complex c5("5.0+3.0i"); // 字符串到Complex
Complex c6 = std::string("2.0"); // 隐式转换
// 在表达式中使用
Complex result = c1 + 10.5; // 10.5被隐式转换为Complex(10.5, 0)
// 类型转换运算符
double realPart = static_cast<double>(c1); // 显式转换
}
2.2 constexpr 构造函数(C++11)
在编译期求值的构造函数。
class Point3D {
private:
double x, y, z;
public:
// constexpr构造函数 - 可以在编译期调用
constexpr Point3D(double xVal = 0.0, double yVal = 0.0, double zVal = 0.0)
: x(xVal), y(yVal), z(zVal) {
// constexpr构造函数体必须为空或只包含简单语句
}
// constexpr成员函数
constexpr double getX() const { return x; }
constexpr double getY() const { return y; }
constexpr double getZ() const { return z; }
constexpr double distanceSquared() const {
return x * x + y * y + z * z;
}
// C++14起可以在constexpr函数中有更多操作
constexpr void translate(double dx, double dy, double dz) {
x += dx;
y += dy;
z += dz;
}
};
// 编译期计算
constexpr Point3D origin; // 编译期构造
constexpr Point3D p1(1.0, 2.0, 3.0); // 编译期构造
constexpr double dist = p1.distanceSquared(); // 编译期计算
constexpr Point3D p2 = []() { // C++17起
Point3D p(1.0, 1.0, 1.0);
p.translate(1.0, 1.0, 1.0); // (2.0, 2.0, 2.0)
return p;
}();
// 运行时使用(与普通类无区别)
Point3D runtimePoint(rand() % 100, rand() % 100, rand() % 100);
2.3 模板构造函数
基于模板参数的构造函数。
template<typename T>
class Container {
private:
T* data;
size_t capacity;
size_t size;
public:
// 普通构造函数
Container(size_t cap = 10) : capacity(cap), size(0) {
data = new T[capacity];
std::cout << "Container<" << typeid(T).name()
<< "> constructor, capacity: " << capacity << "\n";
}
// 模板构造函数:从其他类型的Container转换
template<typename U>
Container(const Container<U>& other)
: capacity(other.getCapacity()), size(other.getSize()) {
data = new T[capacity];
// 转换每个元素
for (size_t i = 0; i < size; ++i) {
data[i] = static_cast<T>(other[i]);
}
std::cout << "Template conversion constructor from Container<"
<< typeid(U).name() << ">\n";
}
// 模板构造函数:从迭代器范围构造
template<typename InputIt>
Container(InputIt first, InputIt last) {
size = capacity = std::distance(first, last);
data = new T[capacity];
std::copy(first, last, data);
std::cout << "Iterator range constructor\n";
}
~Container() {
delete[] data;
}
size_t getCapacity() const { return capacity; }
size_t getSize() const { return size; }
T& operator[](size_t index) { return data[index]; }
const T& operator[](size_t index) const { return data[index]; }
};
// 使用模板构造函数
void demonstrateTemplateConstructor() {
Container<int> intContainer(5);
intContainer[0] = 1;
intContainer[1] = 2;
// 使用模板转换构造函数
Container<double> doubleContainer(intContainer); // int -> double
// 使用迭代器范围构造函数
std::vector<std::string> vec = {"Hello", "World", "Template"};
Container<std::string> strContainer(vec.begin(), vec.end());
// 从数组构造
int arr[] = {10, 20, 30, 40};
Container<int> arrContainer(std::begin(arr), std::end(arr));
}
2.4 显式默认构造函数(= default)(C++11)
显式要求编译器生成默认实现。
class ModernClass {
private:
std::string name;
int id;
std::vector<double> values;
public:
// 显式默认构造函数
ModernClass() = default;
// 参数化构造函数
ModernClass(const std::string& n, int i) : name(n), id(i) {}
// 显式默认拷贝构造函数
ModernClass(const ModernClass&) = default;
// 显式默认移动构造函数
ModernClass(ModernClass&&) = default;
// 显式默认析构函数
~ModernClass() = default;
// 显式默认拷贝赋值运算符
ModernClass& operator=(const ModernClass&) = default;
// 显式默认移动赋值运算符
ModernClass& operator=(ModernClass&&) = default;
// 删除特定函数
ModernClass(int) = delete; // 禁止从int构造
void display() const {
std::cout << "Name: " << name << ", ID: " << id
<< ", Values count: " << values.size() << "\n";
}
};
// 对比传统写法
class TraditionalClass {
private:
std::string name;
int id;
std::vector<double> values;
public:
// 传统写法:需要手动实现所有特殊成员函数
TraditionalClass() {} // 空实现
TraditionalClass(const TraditionalClass& other)
: name(other.name), id(other.id), values(other.values) {}
TraditionalClass(TraditionalClass&& other) noexcept
: name(std::move(other.name)), id(other.id),
values(std::move(other.values)) {
other.id = 0;
}
~TraditionalClass() {} // 空析构函数
TraditionalClass& operator=(const TraditionalClass& other) {
if (this != &other) {
name = other.name;
id = other.id;
values = other.values;
}
return *this;
}
TraditionalClass& operator=(TraditionalClass&& other) noexcept {
if (this != &other) {
name = std::move(other.name);
id = other.id;
values = std::move(other.values);
other.id = 0;
}
return *this;
}
};
2.5 显式删除构造函数(= delete)(C++11)
禁止特定的构造函数。
class NonCopyable {
private:
int* resource;
public:
NonCopyable(int value = 0) : resource(new int(value)) {
std::cout << "NonCopyable constructor: " << value << "\n";
}
// 删除拷贝构造函数 - 禁止拷贝
NonCopyable(const NonCopyable&) = delete;
// 删除拷贝赋值运算符
NonCopyable& operator=(const NonCopyable&) = delete;
// 允许移动
NonCopyable(NonCopyable&& other) noexcept
: resource(other.resource) {
other.resource = nullptr;
std::cout << "NonCopyable move constructor\n";
}
NonCopyable& operator=(NonCopyable&& other) noexcept {
if (this != &other) {
delete resource;
resource = other.resource;
other.resource = nullptr;
}
return *this;
}
~NonCopyable() {
delete resource;
}
int getValue() const {
return resource ? *resource : -1;
}
};
class Singleton {
private:
static Singleton* instance;
int data;
// 私有构造函数 - 禁止外部创建
Singleton() : data(0) {}
// 删除拷贝和移动构造函数
Singleton(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton& operator=(Singleton&&) = delete;
public:
static Singleton& getInstance() {
if (!instance) {
instance = new Singleton();
}
return *instance;
}
void setData(int val) { data = val; }
int getData() const { return data; }
// 注意:需要单独实现清理逻辑
static void destroy() {
delete instance;
instance = nullptr;
}
};
// 使用
void demonstrateDeletedConstructors() {
NonCopyable nc1(42);
// NonCopyable nc2 = nc1; // ❌ 错误:拷贝构造函数被删除
// nc2 = nc1; // ❌ 错误:拷贝赋值被删除
NonCopyable nc3 = std::move(nc1); // ✅ 允许移动
Singleton& s1 = Singleton::getInstance();
// Singleton s2 = s1; // ❌ 错误:拷贝构造函数被删除
// Singleton s3; // ❌ 错误:构造函数私有
}
三、构造函数的特殊特性
3.1 初始化列表(Initializer List)
在构造函数体执行前初始化成员。
class InitializationDemo {
private:
const int constMember; // 必须在初始化列表初始化
int& refMember; // 必须在初始化列表初始化
int normalMember;
std::string strMember;
std::vector<int> vecMember;
public:
// 正确的初始化列表
InitializationDemo(int x, int& ref, const std::string& str)
: constMember(x), // 常量成员
refMember(ref), // 引用成员
normalMember(0), // 普通成员
strMember(str), // 类类型成员
vecMember{1, 2, 3, 4} { // 使用初始化列表初始化vector
// 构造函数体
normalMember = 10; // 可以在构造函数体中赋值
// constMember = 20; // ❌ 错误:常量成员不能在构造函数体中赋值
// refMember = ref; // ❌ 错误:引用必须在初始化列表初始化
}
// 初始化顺序取决于成员声明顺序,而不是初始化列表顺序
class OrderMatters {
int a;
int b;
public:
// 危险:初始化顺序是a先于b,但列表中是b先于a
OrderMatters(int val) : b(val), a(b + 1) { // a(b+1)先执行,但b未初始化!
std::cout << "a = " << a << ", b = " << b << "\n";
}
};
void display() const {
std::cout << "constMember: " << constMember
<< ", refMember: " << refMember
<< ", normalMember: " << normalMember
<< ", strMember: " << strMember
<< ", vec size: " << vecMember.size() << "\n";
}
};
3.2 noexcept 构造函数
声明构造函数不会抛出异常。
class NoThrowClass {
private:
std::unique_ptr<int[]> data;
size_t size;
public:
// noexcept构造函数 - 承诺不抛出异常
NoThrowClass(size_t n) noexcept
: data(std::make_unique<int[]>(n)), size(n) {
// 这里不能抛出异常,否则程序会调用std::terminate
std::fill(data.get(), data.get() + size, 0);
}
// 移动构造函数也应该是noexcept
NoThrowClass(NoThrowClass&& other) noexcept
: data(std::move(other.data)), size(other.size) {
other.size = 0;
}
// noexcept的重要性:标准库容器在重新分配内存时会使用移动
// 如果移动构造函数不是noexcept,则会使用拷贝
// 标记可能抛出异常的构造函数
NoThrowClass(const std::string& filename)
: data(nullptr), size(0) {
// 文件操作可能抛出异常
std::ifstream file(filename);
if (!file) {
throw std::runtime_error("Cannot open file");
}
// ... 读取数据
}
};
// 使用noexcept构造函数
void demonstrateNoexcept() {
std::vector<NoThrowClass> objects;
// 由于移动构造函数是noexcept,vector重新分配时会使用移动
for (int i = 0; i < 100; ++i) {
objects.emplace_back(100); // 高效移动,不会拷贝
}
}
3.3 私有/受保护构造函数
控制对象的创建方式。
class FactoryPattern {
private:
int id;
std::string type;
// 私有构造函数 - 只能通过工厂方法创建
FactoryPattern(int i, const std::string& t) : id(i), type(t) {}
public:
// 工厂方法
static std::unique_ptr<FactoryPattern> createObjectA(int id) {
return std::make_unique<FactoryPattern>(id, "TypeA");
}
static std::shared_ptr<FactoryPattern> createObjectB(int id) {
return std::make_shared<FactoryPattern>(id, "TypeB");
}
static FactoryPattern createObjectC(int id) {
return FactoryPattern(id, "TypeC"); // C++17起保证RVO
}
// 也可以创建不同子类
class SubTypeA : public FactoryPattern {
private:
SubTypeA(int id) : FactoryPattern(id, "SubTypeA") {}
public:
static std::unique_ptr<SubTypeA> create(int id) {
return std::make_unique<SubTypeA>(id);
}
};
};
class BuilderPattern {
private:
std::string name;
int value;
double factor;
// 私有构造函数 - 只能通过Builder创建
BuilderPattern(const std::string& n, int v, double f)
: name(n), value(v), factor(f) {}
public:
// Builder类
class Builder {
private:
std::string name;
int value = 0;
double factor = 1.0;
public:
Builder& setName(const std::string& n) {
name = n;
return *this;
}
Builder& setValue(int v) {
value = v;
return *this;
}
Builder& setFactor(double f) {
factor = f;
return *this;
}
BuilderPattern build() {
if (name.empty()) {
throw std::invalid_argument("Name cannot be empty");
}
return BuilderPattern(name, value, factor);
}
};
static Builder createBuilder() {
return Builder();
}
void display() const {
std::cout << "Name: " << name << ", Value: " << value
<< ", Factor: " << factor << "\n";
}
};
// 使用
void demonstratePrivateConstructors() {
// Factory模式
auto obj1 = FactoryPattern::createObjectA(1);
auto obj2 = FactoryPattern::createObjectB(2);
auto obj3 = FactoryPattern::createObjectC(3);
auto subObj = FactoryPattern::SubTypeA::create(4);
// Builder模式
auto builder = BuilderPattern::createBuilder();
auto builtObj = builder.setName("Test")
.setValue(100)
.setFactor(2.5)
.build();
builtObj.display();
}
四、构造函数的高级应用
4.1 完美转发构造函数
template<typename T>
class Wrapper {
private:
T wrappedObject;
public:
// 完美转发构造函数
template<typename... Args>
explicit Wrapper(Args&&... args)
: wrappedObject(std::forward<Args>(args)...) {
std::cout << "Wrapper perfect-forwarding constructor\n";
}
// 拷贝构造函数(需要单独定义,否则模板会覆盖)
Wrapper(const Wrapper& other)
: wrappedObject(other.wrappedObject) {
std::cout << "Wrapper copy constructor\n";
}
// 移动构造函数
Wrapper(Wrapper&& other) noexcept
: wrappedObject(std::move(other.wrappedObject)) {
std::cout << "Wrapper move constructor\n";
}
const T& get() const { return wrappedObject; }
T& get() { return wrappedObject; }
};
// 使用完美转发
void demonstratePerfectForwarding() {
// 各种构造方式都能正确转发
Wrapper<std::string> ws1("Hello"); // 从const char*构造
Wrapper<std::string> ws2(5, 'A'); // 从count和char构造
Wrapper<std::vector<int>> wv1{1, 2, 3, 4}; // 初始化列表
Wrapper<std::vector<int>> wv2(10, 42); // 从count和value构造
// 自定义类型
class ComplexType {
public:
ComplexType(int a, double b, const std::string& c) {
std::cout << "ComplexType constructor\n";
}
};
Wrapper<ComplexType> wc(42, 3.14, "test"); // 完美转发多个参数
}
4.2 SFINAE 约束的构造函数
template<typename T>
class SmartContainer {
private:
std::vector<T> data;
public:
// SFINAE:只有T可默认构造时才启用此构造函数
template<typename U = T,
typename = std::enable_if_t<std::is_default_constructible_v<U>>>
SmartContainer(size_t size) : data(size) {
std::cout << "Default value constructor, size: " << size << "\n";
}
// 只有T可拷贝构造时才启用
template<typename U = T,
typename = std::enable_if_t<std::is_copy_constructible_v<U>>>
SmartContainer(size_t size, const T& value) : data(size, value) {
std::cout << "Fill constructor, size: " << size << "\n";
}
// 只有T可从迭代器构造时才启用
template<typename InputIt,
typename = std::enable_if_t<
std::is_constructible_v<T,
typename std::iterator_traits<InputIt>::value_type>>>
SmartContainer(InputIt first, InputIt last) : data(first, last) {
std::cout << "Iterator range constructor\n";
}
// C++20概念(更简洁)
/*
SmartContainer(size_t size) requires std::default_initializable<T>
: data(size) {}
SmartContainer(size_t size, const T& value) requires std::copyable<T>
: data(size, value) {}
template<std::input_iterator InputIt>
SmartContainer(InputIt first, InputIt last) : data(first, last) {}
*/
};
// 使用SFINAE构造函数
void demonstrateSFINAE() {
// 对于可默认构造的类型
SmartContainer<int> sci1(10); // 调用默认值构造函数
SmartContainer<int> sci2(10, 42); // 调用填充构造函数
// 对于不可默认构造的类型
class NoDefault {
public:
NoDefault() = delete;
NoDefault(int) {}
};
SmartContainer<NoDefault> scn1(10, NoDefault(42)); // OK:填充构造
// SmartContainer<NoDefault> scn2(10); // ❌ 错误:没有默认构造函数
}
五、构造函数调用顺序总结
class Base {
public:
Base() { std::cout << "Base constructor\n"; }
virtual ~Base() { std::cout << "Base destructor\n"; }
};
class Member {
public:
Member() { std::cout << "Member constructor\n"; }
~Member() { std::cout << "Member destructor\n"; }
};
class Derived : public Base {
private:
Member member;
int value;
public:
// 构造顺序:
// 1. 基类构造函数
// 2. 成员变量构造函数(按声明顺序)
// 3. 派生类构造函数体
Derived(int v) : Base(), value(v) { // 初始化列表顺序不影响实际顺序
std::cout << "Derived constructor, value = " << value << "\n";
}
// 析构顺序(相反):
// 1. 派生类析构函数体
// 2. 成员变量析构函数(按声明顺序的逆序)
// 3. 基类析构函数
~Derived() {
std::cout << "Derived destructor\n";
}
};
// 多重继承
class Base1 {
public:
Base1() { std::cout << "Base1 constructor\n"; }
};
class Base2 {
public:
Base2() { std::cout << "Base2 constructor\n"; }
};
class MultipleDerived : public Base1, public Base2 {
public:
// 构造顺序:
// 1. Base1构造函数
// 2. Base2构造函数
// 3. MultipleDerived构造函数体
MultipleDerived() {
std::cout << "MultipleDerived constructor\n";
}
};
// 虚继承
class VirtualBase {
public:
VirtualBase() { std::cout << "VirtualBase constructor\n"; }
};
class VirtualDerived1 : virtual public VirtualBase {
public:
VirtualDerived1() { std::cout << "VirtualDerived1 constructor\n"; }
};
class VirtualDerived2 : virtual public VirtualBase {
public:
VirtualDerived2() { std::cout << "VirtualDerived2 constructor\n"; }
};
class DiamondDerived : public VirtualDerived1, public VirtualDerived2 {
public:
// 虚基类只构造一次
// 构造顺序:
// 1. VirtualBase构造函数(虚基类优先)
// 2. VirtualDerived1构造函数
// 3. VirtualDerived2构造函数
// 4. DiamondDerived构造函数体
DiamondDerived() {
std::cout << "DiamondDerived constructor\n";
}
};
六、最佳实践总结
-
使用初始化列表初始化所有成员,特别是常量和引用
-
按声明顺序编写初始化列表
-
对于简单类 使用
= default -
对于资源管理类定义拷贝/移动构造函数和赋值运算符
-
使用
explicit防止意外的隐式转换 -
移动构造函数 应该标记为
noexcept -
单参数构造函数 考虑是否需要
explicit -
委托构造函数避免代码重复
-
模板构造函数注意不要隐藏拷贝/移动构造函数
-
考虑使用工厂模式而不是复杂的构造函数
构造函数是C++对象生命周期的起点,合理使用各种构造函数可以提高代码的健壮性、安全性和性能。