在现代C++编程中,构造函数扮演着初始化对象状态的重要角色。随着语言的发展,C++11引入了两个强大的构造机制——委托构造(Delegating Constructors)和继承构造(Inheriting Constructors),它们均增强了代码复用,减少重复代码,提高了代码的可读性和可维护性。
委托构造(Delegating Constructors)
当一个类存在需要多种初始化方式,且不同初始化方式间存在部分相同的初始化逻辑。在C++11之前,需要在每个构造函数内部重复相同的初始化代码,或者通过一个初始化函数来集中处理这些共性操作。C++11引入了委托构造,委托构造允许一个构造函数直接调用另一个构造函数来完成初始化工作,从而避免代码重复和提高可维护性。
示例代码如下:
class People {
public:
People():People("lucy",33){};
explicit People(std::string name):People(name,18){}
explicit People(std::string nam, int age):m_name{nam},m_age{age}{}
[[nodiscard]] const int GetAge() const
{
return m_age;
}
private:
int m_age{0};
std::string m_name{""};
};
由以上代码可知,无参和单参的构造函数均委托给了两个入参的构造函数,实现了代码的复用和简化。
继承构造(Inheriting Constructors)
当一个类继承自另一个类时,继承构造允许子类自动继承父类的构造函数,这对于保持接口一致性和简化代码非常有用。这意味着,如果父类有一个或多个构造函数,子类可以直接使用这些构造函数而无需显式重写。
示例代码如下:
class People {
public:
virtual ~People()=default;
People():People("lucy",33){}
explicit People(std::string name):People(name,18){}
explicit People(std::string nam, int age):m_name{nam},m_age{age}{}
[[nodiscard]] const int GetAge() const {
return m_age;
}
[[nodiscard]] const std::string GetName() const{
return m_name;
}
private:
int m_age{0};
std::string m_name{""};
};
class Student : public People {
public:
// 继承构造声明,People
using People::People;
Student(std::string name, int age, int class_num):People(name,age),m_class_number{class_num}{}
[[nodiscard]] const int GetClassNum() const {
return m_class_number;
}
private:
int m_class_number{0};
};
void test_People()
{
People tom{"tom"};
People Rocky{"rocky",25};
}
void PrintStudent(const Student& s)
{
std::cout<<"name:"<<s.GetName()<<"\t"<<"age:"<<s.GetAge()<<"\t"<<"class_num:"<<s.GetClassNum()<<"\n";
}
void test_student()
{
Student s1;//此处需要C++17方可成功
PrintStudent(s1);
Student s2{"s2"};
PrintStudent(s2);
Student s3{ "s3",18 };
PrintStudent(s3);
Student s4{"s4",36,332};
PrintStudent(s4);
}
由如上代码可知,Student类通过using People::People;语句继承了People类的所有构造函数;同时Student定义了自身的构造函数,只是子类继承父类的无参构造函数需要是C++17及其以上版本。
结论
委托构造简化了多个构造函数中含有相同逻辑的书写方式,有助于保持代码的DRY(Don't Repeat Yourself)原则,减少错误,并使代码更加清晰。继承构造简化了派生类的定义过程,特别是当基类有复杂的构造逻辑时,避免了手动复制构造函数的繁琐工作。两者均简化了代码,提高了复用性。