2、给继承类添加虚基类成员函数的重载

        给继承类添加新的虚基类成员函数的重载是可能的。也就是说,可以用新的原型给继承类中的虚成员函数添加重载,但是继续继承基类版本。这个技术使用了using声明来显式包含了继承类中的成员函数的基类定义。下面为示例:

class Base
{
public:
    virtual void someFunction();
};

class Derived : public Base
{
public:
    using Base::someFunction;    // Explicitly inherits the Base version.
    virtual void someFunction(int i); // Adds a new overload of someFunction().
    virtual void someOtherFunction();
};

        注意:在继承类中具有与基类同名但使用不同的参数列表的成员函数是很少见的。

2.1、继承构造函数

        在前面的章节中,可以看到在继承类中使用using声明显式包含了基类的成员函数的定义。对于正常类的成员函数是有效的,对于构造函数也有效,允许从基类继承构造函数。看一下Base与Derived类的如下定义:

class Base
{
public:
    virtual  ̃Base() = default;
    Base() = default;
    explicit Base(int i) {}
};

class Derived : public Base
{
public:
    explicit Derived(int i) : Base(i) {}
};

        Derived构造函数只做了一件事,将它的参数传递给了Base构造函数。

        只用提供的Base构造函数就可以构建一个Base对象,或者是缺省的构造函数,或者是接受int的构造函数。另一方面,可以只用提供的Derived构造函数构建一个Derived对象,要求一个单独的整数作为参数。

        不能使用缺省的Base类的构造函数可构建Derived对象。如下示例:

Base base { 1 };        // OK, calls integer Base ctor.
Derived derived1 { 2 };    // OK, calls integer Derived ctor.
Derived derived2;    // Error, Derived does not have a default ctor.

        由于Derived构造函数只是传递参数给Base构造函数,没有做任何其它事,可以显示使用using声明在Derived类中简单继承Base构造函数如下:

class Derived : public Base
{
public:
    using Base::Base;
};

        using声明继承了所有的Base的构造函数,所以现在可以用如下的方式构建Derived对象了:

Derived derived1 { 2 };    // OK, calls inherited integer Base ctor.
Derived derived2;        // OK, calls inherited default Base ctor.

        继承类中的继承的构造函数拥有与基类构造函数同样的访问指示符(公共,受保护,或私有)。在基类中使用=delete显式删除的继承构造函数在继承类也会被删除。

2.2、隐藏继承构造函数

        Derived类可以定义与在基类中继承的构造函数同样的参数列表的构造函数。在这种情况下,Derived类的优先级高于继承的构造函数。在下面的例子中,Derived类使用using声明从Base类中继承了所有的构造函数。然而,因为Derived类用单独的float类型的参数定义它自己的构造函数,使用单独的float类型的参数的基类中继承的构造函数就被隐藏了。

class Base
{
public:
	virtual ~Base() = default;
	Base() = default;
	explicit Base(std::string_view str) {}
	explicit Base(float f) {}
};

class Derived : public Base
{
public:
	using Base::Base;
	explicit Derived(float f) {}    // Hides inherited float Base ctor
};

        使用这个定义,Derived对象可以生成如下:

	Derived derived1{ "Hello" };   // OK, calls inherited string_view Base ctor
	Derived derived2{ 1.23f };     // OK, calls float Derived ctor
	Derived derived3;              // OK, calls inherited default Base ctor.

        使用using声明从基类继承的构造函数的应用有几个限制。

  • 当从基类继承构造函数时,就继承了全部。从基类中只继承部分构造函数是不可能的。
  • 当继承构造函数时,就继承了基类中同样的访问标示,与using声明的访问标示无关。

2.3、继承构造函数与多重继承

        另外一个与继承构造函数相关的限制是多重继承。如果另一个基类有一个同样参数列表的构造函数是不能从其中一个基类继承构造函数的,因为这会带来不确定性。为了解决这个问题,Derived类需要显式定义冲突的构造函数。例如,如下的Derived类尝试继承Based1与Base2的所有构造函数,对于基于float的构造函数就产生了不确定性。

import std;

class Base1
{
public:
	virtual ~Base1() = default;
	Base1() = default;
	explicit Base1(float f) {}
};

class Base2
{
public:
	virtual ~Base2() = default;
	Base2() = default;
	explicit Base2(std::string_view str) {}
	explicit Base2(float f) {}
};

class Derived : public Base1, public Base2
{
public:
	using Base1::Base1;
	using Base2::Base2;
	explicit Derived(char c) {}
	explicit Derived(float f) : Base1{ f }, Base2{ f } {}
};


int main()
{
	Derived d{ 1.2f };
}

        在Derived中的第一个using声明继承了Base1的所有构造函数。这意味着Derived获得了如下的构造函数:

Derived(float f);       // Inherited from Base1.

        在Derived中的第二个using声明尝试继承Base2的所有构造函数。然而,这意味着Derived获得了第二个Derived(float)构造函数。该问题可以通过在Derived中显式声明冲突的构造函数,如下:

class Derived : public Base1, public Base2
{
public:
    using Base1::Base1;
    using Base2::Base2;

    explicit Derived(char c) {}
    explicit Derived(float f) {}
};

        现在Derived类显式声明了一个带有单个float类型的参数的构造函数,解决了不确定性。如果你想,在Derived类中接受float参数的显式声明的构造函数仍然可以在构造函数初始化器中可以传递对Base1与Base2的构造函数的调用,如下:

Derived::Derived(float f) : Base1 { f }, Base2 { f } {}

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部