这是C++11里的知识,如果所用的编译器不支持,直接忽视;
我用的IED:visual stadio 2019。
1、继承构造函数
构造函数非常重要,但有时候真是又爱又恨,尤其是在一些类的继承中,子类和基类的构造函数完全相同,却需要将所有基类的构造函数全部重新写一遍,非常厌烦。
C++11推出了继承构造函数的概念,对于很多继承类,无需再重复编写完全一样的构造函数。
例如,公司根据职工的能力不同分为不同等级,各个等级的基本工资和绩效工资都不一样,绩效工资与各个月的绩效系数挂钩。据此,可以设计出很简单的代码结构,如下:
#include <iostream>
class Employee
{
public:
explicit Employee(const std::string& strName):m_strName(strName), m_dRatio(1){}
Employee(const std::string& strName, double dRatio) :m_strName(strName), m_dRatio(dRatio) {}
const std::string& GetName() const { return m_strName; }
double ActualPrice() const { return GetRegularWage() + GetMeritPay() * m_dRatio; }
protected:
/// @brief 基本工资
virtual double GetRegularWage() const = 0;
/// @brief 绩效工资
virtual double GetMeritPay() const = 0;
protected:
double m_dRatio; //绩效系数
std::string m_strName; //名字
};
class Grade1 : public Employee
{
public:
using Employee::Employee;
protected:
virtual double GetRegularWage() const override { return 5000; }
virtual double GetMeritPay() const override { return 3000; }
};
class Grade2 : public Employee
{
public:
using Employee::Employee;
protected:
virtual double GetRegularWage() const override { return 6000; }
virtual double GetMeritPay() const override { return 4000; }
};
void PrintInfo(const Employee& r)
{
std::cout << r.GetName() << "的工资:" << r.ActualPrice() << "\n";
}
int main()
{
Grade1 em1("张三");
Grade2 em2("李四", 0.4);
PrintInfo(em1);
PrintInfo(em2);
system("pause");
return 0;
}
程序很简单,有一个职工的基类Employee,包含两个成员变量:名称和绩效系数。有两个重载的构造函数,一个只需要指定员工姓名,绩效默认为1;另一个需要指定姓名和绩效。
基类中有一个获取实际工资的接口,实现很简单:实际工资=基本工资+绩效工资*绩效系数。基本工资和绩效工资都是纯虚函数,由各个子类实现。
两个子类,Grade1和Grade2,表示不同的等级。这两个基类仅需要实现获取基本工资和绩效工资的虚函数即可,没有任何其他信息。如果是之前,必须要各写两个构造函数,构造函数中再调用子类的相应构造函数。用了C++11,直接写:using Employee::Employee; 即可。
main函数的对象实例化可以看出来,基类Employee的两种构造函数均被继承了下来,非常方便。
运行结果如下:
2、委派构造函数
委派构造函数,就是将某个构造函数,委派给其他的构造函数实现。
类似上面的例子,基类Employee有两个构造函数,功能很类似。仅传一个名字的构造函数,其实就是调用另一个构造函数绩效系数设为1。
修改Employee,实现如下:
class Employee
{
public:
explicit Employee(const std::string& strName):Employee(strName, 1){} //将实现委派给另一个构造函数
Employee(const std::string& strName, double dRatio) :m_strName(strName), m_dRatio(dRatio) {}
const std::string& GetName() const { return m_strName; }
double ActualPrice() const { return GetRegularWage() + GetMeritPay() * m_dRatio; }
protected:
/// @brief 基本工资
virtual double GetRegularWage() const = 0;
/// @brief 绩效工资
virtual double GetMeritPay() const = 0;
protected:
double m_dRatio; //绩效系数
std::string m_strName; //名字
};
可以看到,explicit Employee(const std::string& strName)构造函数,调用的是另一个构造函数,将系数设为1。这个调用其他构造函数实现自身的被称为委派构造函数,而被调用的构造函数被称为目标构造函数。
执行结果如下:
完全没有变化。
委派构造函数有以下几点需要注意:
1、委派构造函数不能有初始化列表;
2、目标构造函数的执行总是先于委派构造函数;
3、避免目标构造函数和委派构造函数中初始化同样的成员变量;
4、不能形成委托环。