【问题标题】:Using C++ base class constructors?使用 C++ 基类构造函数?
【发布时间】:2011-12-26 23:46:46
【问题描述】:

在使用模板时,我遇到了需要使基类构造函数可以从继承的类中访问以创建对象以减少复制/粘贴操作。 我正在考虑通过 using 关键字以与函数大小写相同的方式执行此操作,但这不起作用。

class A
{
public: 
    A(int val) {}
};

class B : public A
{
};

class C : public A
{
public:
    C(const string &val) {}
};

class D : public A
{
public:
    D(const string &val) {}
    using A::A;              // g++ error: A::A names constructor
};

void main()
{
    B b(10);                // Ok.   (A::A constructor is not overlapped)
    C c(10);                // error: no matching function to call to 'C::C(int)'
}

所以我的问题是:有没有办法在继承类中的新构造函数被声明后导入基类构造函数?

或者只有一种替代方法可以声明新的构造函数并从初始化列表中调用基础构造函数?

【问题讨论】:

标签: c++ inheritance constructor c++11


【解决方案1】:

是的,从 C++11 开始:

struct B2 {
    B2(int = 13, int = 42);
};
struct D2 : B2 {
    using B2::B2;
// The set of inherited constructors is
// 1. B2(const B2&)
// 2. B2(B2&&)
// 3. B2(int = 13, int = 42)
// 4. B2(int = 13)
// 5. B2()

// D2 has the following constructors:
// 1. D2()
// 2. D2(const D2&)
// 3. D2(D2&&)
// 4. D2(int, int) <- inherited
// 5. D2(int) <- inherited
};

更多信息请见http://en.cppreference.com/w/cpp/language/using_declaration

【讨论】:

  • 这对我不起作用。我得到一个“没有构造函数实例与参数列表匹配”。
  • @charlesrockbass 这意味着您的 B2 没有与您的参数列表匹配的构造函数,或者构造函数无法访问
【解决方案2】:

不,不是这样的。初始化基类的常规方法是在初始化列表中:

class A
{
public: 
    A(int val) {}
};

class B : public A
{
public:
  B( int v) : A( v )
  {
  }
};


void main()
{
    B b(10);
}

【讨论】:

    【解决方案3】:

    首选初始化:

    class C : public A
    {
    public:
        C(const string &val) : A(anInt) {}
    };
    

    在 C++11 中,您可以使用继承构造函数(其语法在您的示例 D 中可见)。

    更新:继承构造函数自 4.8 版开始在 GCC 中可用。


    如果您觉得初始化不吸引人(例如,由于您的实际案例中存在多种可能性),那么对于某些 TMP 构造,您可能会喜欢这种方法:

    class A
    {
    public: 
        A() {}
        virtual ~A() {}
        void init(int) { std::cout << "A\n"; }
    };
    
    class B : public A
    {
    public:
        B() : A() {}
        void init(int) { std::cout << "B\n"; }
    };
    
    class C : public A
    {
    public:
        C() : A() {}
        void init(int) { std::cout << "C\n"; }
    };
    
    class D : public A
    {
    public:
        D() : A() {}
        using A::init;
        void init(const std::string& s) { std::cout << "D -> " << s << "\n"; }
    };
    
    int main()
    {
        B b; b.init(10);
        C c; c.init(10);
        D d; d.init(10); d.init("a");
    
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      您需要在每个派生类中声明构造函数,然后从初始化列表中调用基类构造函数:

      class D : public A
      {
      public:
          D(const string &val) : A(0) {}
          D( int val ) : A( val ) {}
      };
      
      D variable1( "Hello" );
      D variable2( 10 );
      

      C++11 允许您使用在 D 的声明中使用的 using A::A 语法,但目前并非所有编译器都支持 C++11 功能,因此最好坚持使用较旧的 C++方法,直到此功能在您的代码将使用的所有编译器中实现。

      【讨论】:

      • 你确定它可以编译吗? A 在第一个构造函数中是如何初始化的?
      • 啊,是的,这个例子有点匆忙。现已修复。
      【解决方案5】:

      这是关于superclass constructor calling rules 的一个很好的讨论。您总是希望在派生类构造函数之前调用基类构造函数,以便正确地形成对象。这就是为什么使用这种形式

        B( int v) : A( v )
        {
        }
      

      【讨论】:

        猜你喜欢
        • 2013-03-24
        • 2015-08-18
        • 1970-01-01
        • 2018-05-25
        • 1970-01-01
        • 2016-07-19
        • 2020-11-28
        • 2012-09-28
        • 1970-01-01
        相关资源
        最近更新 更多