C++ 语言特性10 - 委托构造函数
1:什么是委托构造函数?
在C++中,委托构造函数(Delegating Constructor)是一种特殊的构造函数,它在构造函数的初始化列表中调用同一个类中的另一个构造函数,从而实现代码的复用。这种特性在C++11中引入。
class MyClass {
public:
// 委托构造函数
MyClass(int x, int y) : MyClass(x) {
// 委托给另一个构造函数
}
// 被委托的构造函数
MyClass(int x) {
// 初始化代码
}
};
2. 委托构造函数在什么场景中使用?
-
代码复用: 当多个构造函数需要执行相同的初始化步骤时,可以使用委托构造函数来避免代码重复。
#include <iostream>
#include <string>
class Person {
public:
Person() : Person("Unknown", 0) {
std::cout << "Default constructor called\n";
}
Person(std::string name) : Person(name, 0) {
std::cout << "Name constructor called\n";
}
Person(std::string name, int age) : name(name), age(age) {
std::cout << "Full constructor called for " << name << std::endl;
}
private:
std::string name;
int age;
};
int main() {
Person p1;
Person p2("Alice");
Person p3("Bob", 30);
return 0;
}
-
链式委托: 一个构造函数可以委托给另一个构造函数,而后者又可以委托给下一个,形成一个委托链。
class Matrix {
public:
Matrix() : Matrix(0, nullptr) {
std::cout << "Default constructor called\n";
}
Matrix(size_t rows, size_t cols) : Matrix(rows, cols, new double*[rows]) {
std::cout << "Size constructor called\n";
}
Matrix(size_t rows, size_t cols, double** data) : rows(rows), cols(cols), data(data) {
std::cout << "Data constructor called\n";
}
private:
size_t rows;
size_t cols;
double** data;
};
int main() {
Matrix mat;
return 0;
}
-
继承和覆盖: 在继承的类中,可以利用委托构造函数调用基类的构造函数,以确保正确的初始化。
class Base {
public:
Base(int x) {
std::cout << "Base constructor with int called\n";
}
};
class Derived : public Base {
public:
// 委托给基类的构造函数
Derived(double x) : Base(static_cast<int>(x)) {
std::cout << "Derived constructor with double called\n";
}
};
int main() {
Derived d(3.14);
return 0;
}
3. 注意事项:
-
委托目标的选择: 确保委托的目标构造函数是有效的,并且能够正确初始化对象。
#include <iostream>
#include <string>
#include <vector>
class Data {
public:
// 正确的委托目标选择
Data(const std::string& str) : Data(str.begin(), str.end()) {}
// 正确的初始化列表
Data(const char* begin, const char* end) {
// 做一些初始化工作
for (; begin != end; ++begin) {
values.push_back(*begin);
}
std::cout << "Data initialized with " << values.size() << " elements." << std::endl;
}
private:
std::vector<char> values;
};
int main() {
Data d("Hello");
return 0;
}
-
构造函数的递归调用: 避免构造函数之间的无限递归调用。
class RecursiveConstructor {
public:
// 错误:递归调用自身
RecursiveConstructor() : RecursiveConstructor(42) {}
RecursiveConstructor(int) {
std::cout << "Constructor called" << std::endl;
}
};
int main() {
// RecursiveConstructor rc; // 这将导致无限递归调用
return 0;
}
-
资源管理: 在委托构造函数中,确保资源被正确管理和释放。
#include <iostream>
class Resource {
public:
// 委托构造函数正确地管理资源
Resource(int id) : Resource(id, new int(id * 10)) {
std::cout << "Resource ID: " << *data << std::endl;
}
// 被委托的构造函数
Resource(int id, int* data) : id(id), data(data) {}
~Resource() {
delete data;
}
private:
int id;
int* data;
};
int main() {
Resource res(1);
return 0;
}
//在这个例子中,委托构造函数确保了资源(动态分配的整数)被正确地分配和初始化。
-
异常安全: 委托构造函数需要考虑异常安全性,确保在抛出异常时对象处于一致的状态。
#include <iostream>
#include <string>
class ExceptionSafe {
public:
// 委托构造函数
ExceptionSafe(const std::string& str) : ExceptionSafe(str.begin(), str.end()) {
// 做一些可能会抛出异常的操作
if (str.empty()) {
throw std::invalid_argument("String is empty");
}
}
// 被委托的构造函数
ExceptionSafe(const char* begin, const char* end) {
// 做一些初始化工作
try {
for (; begin != end; ++begin) {
values.push_back(*begin);
}
} catch (...) {
// 异常发生时进行清理工作
std::cout << "Exception caught during initialization." << std::endl;
throw;
}
std::cout << "Data initialized with " << values.size() << " elements." << std::endl;
}
private:
std::vector<char> values;
};
int main() {
try {
ExceptionSafe es("Hello");
ExceptionSafe esEmpty("");
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
}
return 0;
}