在C++11标准中,引入了委托构造函数和继承构造函数这两个重要的特性。这些特性不仅提升了代码的性能,还增强了代码的可读性和可维护性。对于初学者来说,理解和掌握这些特性是迈向高级C++编程的关键一步。本文将详细介绍委托构造函数和继承构造函数的基本概念、使用方法以及实际应用场景,帮助你从入门到精通。
委托构造函数是C++11引入的一个特性,它允许一个构造函数调用同一个类中的另一个构造函数来完成对象的初始化。这种特性可以减少代码冗余,提高代码的可维护性,同时也使得代码结构更加清晰。例如,在一个类中可能有多个构造函数,它们之间存在一些重复的初始化代码,使用委托构造函数可以避免这些重复代码的出现。
委托构造函数的语法格式如下:
class MyClass {
public:
// 目标构造函数
MyClass(int param1, int param2) {
// 构造函数的具体实现
}
// 委托构造函数
MyClass(int param) : MyClass(param, 0) {
// 委托给另一个构造函数完成初始化
}
};
在上述代码中,第一个构造函数接受两个参数,而第二个构造函数只接受一个参数。第二个构造函数使用了初始化列表的方式,通过委托给第一个构造函数来完成对象的初始化。
下面通过一个具体的例子来详细解析委托构造函数的使用:
#include
using namespace std;
class Test {
public:
Test() {};
Test(int max) {
this->m_max = max > 0 ? max : 100;
}
Test(int max, int min) : Test(max) {
this->m_min = min > 0 && min < max ? min : 1;
}
Test(int max, int min, int mid) : Test(max, min) {
this->m_middle = mid < max && mid > min ? mid : 50;
}
int m_min;
int m_max;
int m_middle;
};
int main() {
Test t(90, 30, 60);
cout << "min: " << t.m_min << ", middle: " << t.m_middle << ", max: " << t.m_max << endl;
return 0;
}
在这个例子中,Test(int max, int min)
构造函数委托给 Test(int max)
构造函数,Test(int max, int min, int mid)
构造函数委托给 Test(int max, int min)
构造函数,这样可以避免在多个构造函数中重复初始化 m_max
和 m_min
。
class MyClass {
public:
MyClass(int param1) : MyClass(param1, 0) {
// 委托给另一个构造函数完成初始化
}
MyClass(int param1, int param2) : MyClass(param1) {
// 错误:形成了闭环
}
};
class Test {
public:
Test(int max) {
this->m_max = max > 0 ? max : 100;
}
Test(int max, int min) {
Test(max); // 错误,编译器会报错,提示形参max被重复定义
this->m_min = min > 0 && min < max ? min : 1;
}
};
class Test {
public:
Test(int max, int min) : Test(max), m_max(max) {
// 错误,使用了委托构造函数就不能再次m_max初始化了
this->m_min = min > 0 && min < max ? min : 1;
}
};
在C++11之前,如果基类有多个构造函数,派生类需要为自己需要用到的每一个基类构造函数编写对应的构造函数,即使这些派生类构造函数只是简单地将参数传递给基类构造函数。这不仅增加了代码量,也提高了维护成本。继承构造函数允许派生类继承基类的所有构造函数,从而无需在派生类中显式定义这些构造函数。这样做可以显著减少代码重复,使得派生类的编写更加简洁明了。
继承构造函数的语法格式如下:
class Base {
public:
Base() {
// 默认构造函数的实现
}
Base(int value) {
// 带参数的构造函数实现
}
};
class Derived : public Base {
public:
using Base::Base; // 继承基类的所有构造函数
};
在这个示例中,通过在派生类中使用 using Base::Base;
语句,Derived
类自动继承了 Base
类的所有构造函数。不需要在 Derived
类中显式定义这些构造函数,就可以像使用 Base
类的构造函数那样使用它们来初始化 Derived
类的对象。
下面通过一个具体的例子来详细解析继承构造函数的使用:
#include
#include
using namespace std;
class Base {
public:
Base(int i) : m_i(i) { }
Base(int i, double j) : m_i(i), m_j(j) { }
Base(int i, double j, string k) : m_i(i), m_j(j), m_k(k) { }
int m_i;
double m_j;
string m_k;
};
class Child : public Base {
public:
using Base::Base;
};
int main() {
Child c(520, 13.14, "i love you");
cout << "int: " << c.m_i << ", double: " << c.m_j << ", string: " << c.m_k << endl;
return 0;
}
通过测试代码可以看出,在子类中初始化从基类继承的类成员,使用继承构造函数可以避免在子类中重新定义和基类一致的构造函数,使得代码更加精简。
struct Base1 {
Base1() = default;
Base1(const std::string&);
Base1(std::shared_ptr<int>);
};
struct Base2 {
Base2() = default;
Base2(const std::string&);
Base2(int);
};
// 错误: D1 试图从两个基类中都继承D1::D1(const string&)
struct D1 : public Base1, public Base2 {
using Base1::Base1; //从 Base1 继承构造函数
using Base2::Base2; //从 Base2 继承构造函数
};
在这种情况下,派生类必须为该构造函数定义它自己的版本:
struct D2 : public Base1, public Base2 {
using Base1::Base1; //从 Base1 继承构造函数
using Base2::Base2; //从 Base2 继承构造函数
// D2 必须自定义一个接受 string 的构造函数
D2(const string& s) : Base1(s), Base2(s) { }
D2() = default; // 一旦 D2 定义了它自己的构造函数,则必须出现
};
委托构造函数和继承构造函数是C++11中非常强大的特性,它们为C++程序员提供了更多的编程选择和优化机会。通过使用委托构造函数,我们可以减少代码冗余,提高代码的可维护性;而继承构造函数则可以简化派生类构造函数的编写,提高代码的复用性。在实际编程中,合理运用这些特性可以让我们的代码更加高效、安全和易于理解。希望本文能够帮助你更好地理解和掌握C++11中的委托构造函数和继承构造函数,从而提升你的C++编程水平。