构造函数通过另一个派生类的对象初始化派生类的基础部分

问题描述

假设我有一个基类和2个派生类:

class Base {
   public:
      Base() : m_base(0) { }
   private:
      int m_base; 
};

class Derived1 : public Base {
   public:
      Derived1() : Base(),m_d1(1) { }
   private:
      int m_d1;
};

class Derived2 : public Base {
   public:
      Derived2(): Base(),m_d2(2.5) { }
   private:
      double m_d2;
};

我现在希望重载的构造函数通过Derived2实例初始化其基础部分来构造Derived1实例,在该实例中我遇到了一些不同的方法

  1. 指向初始化器列表中的Derived1 + dynamic_cast +基类复制构造函数的指针:

    Derived2(Derived1 *d1) : Base(*(dynamic_cast<Base*>(d1))),m_d2(3.5) { }

    显然,这存在取消引用无效指针的问题

  2. 引用Base并在调用时强制转换Derived1

    Derived2(const Base &base) : Base(base),m_d2(3.5) { }
    // ...
    Derived1 d1 = Derived1();
    Derived2 d2 = Derived2(static_cast<Base>(d1));
    
  3. 首先调用Base认构造函数,然后初始化每个成员:

    Derived2(Derived *d1) : Base(),m_d2(3.5) {
       if (d1) {
           m_base = d1->base();
       }
     }
    

    但这需要访问Derived1的成员以及Base的成员才能成为protected

当然可以肯定还有另一种更好的方法-那么哪种是实现这一目标的最佳方法,为什么呢?

解决方法

您无需强制转换为基本类型。

您要说的话最直接的翻译是

Derived2(const Derived1& d1): Base(d1),m_d2(2.5) { }

然后您所需要的就是

Derived1 d1;
Derived2 d2(d1);

如果您要接受从Base派生的任何类型:

Derived2(const Base& b): Base(b),m_d2(2.5) { }
,
  1. 初始化程序列表中指向Derived1 + dynamic_cast +基类复制构造函数的指针

不需要指针,不需要动态转换,也不需要将参数限制为Derived1

  1. 在调用时引用Base并强制转换Derived1

这很好,除了强制转换是多余的。一个对象可以隐式转换为其基。

  1. 首先调用Base的默认构造函数,然后初始化每个成员

这毫无意义地复杂,在无法默认初始化base的情况下,这不是选择。


另一种选择是按值传递基数,然后从基值移走:

Derived2(Base base) : Base(std::move(base))

这可以避免从rvalue参数复制。对于示例中的琐碎Base来说,这并不是特别有用,但是对于某些慢速复制的真实示例来说,速度可能要快得多。