2014-01-14 56 views
4

注意:不是C++ 11 Delegated Constructor Pure Virtual Method & Function Calls -- Dangers?的重复。这个其他问题是指一个概念上类似的问题,并不真正为这种情况提供解决方案。C++ 11构造函数的继承和纯虚方法

考虑下面的程序:

#include <iostream> 
using std::cout; 
using std::endl; 

class Base { 
    virtual void init() = 0; // a hook function 
    public: 
    Base(int a, int b) { /* ... */ init(); } 
    Base(char a, int b) { /* ... */ init(); } 
    Base(char a, int b, double* c) { /* ... */ init(); } 
    /* etc. Dozens of constructors */ 
};  

class Derived1 : public Base {  
    void init() { cout << "In Derived1::init()" << endl; }  
    public:  
    using Base::Base;  
};  

class Derived2 : public Base {  
    void init() { cout << "In Derived2::init()" << endl; }  
    public:  
    using Base::Base;  
};  

int main() { 
    Derived1 d1(1, 2); 
    Derived2 d2('a', 3); 
    return 0; 
} 

此代码显然不能运行(尽管它带有警告编译一些编译器)。问题是,实现这种模式的最好方法是什么?假设Base中有几十个派生类和几十个构造函数,重新实现派生类中的Base构造函数(在派生构造函数的主体中调用基础构造函数和init())并不是很理想。

+1

我建议删除许多换行符和空的注释,以便更容易理解在类似的小浏览器窗口中找到完整的代码。 – dornhege

回答

2

该代码需要在派生类构造函数中进行,直到对象具有派生类型才能运行该代码。

但是你可以一次用完美转发其添加到所有构造函数:

class Derived1 : public Base 
{ 
public: 
    template<typename... T> 
    explicit Derived1(T&&... t) : Base(std::forward<T>(t)...) { 
     std::cout << "Derived1::init logic goes here" << endl; 
    } 
}; 
+0

@DavidHollman:是的,没有。模板构造函数永远不会是复制或移动构造函数,因此按值传递不会使用该模板。但是当你直接调用一个构造函数时,你可能会得到不想要的结果。见http://akrzemi1.wordpress.com/2013/10/10/too-perfect-forwarding/ –

+0

(重新发布,以便您的评论将有意义)这不会重载默认的副本和移动构造函数? –

0

使这些类的,这个对象创建后调用init()专业厂家

1

另一种方法是“命名'构造函数:

#include <iostream> 

class Base 
{ 
    public: 
    template <typename Derived> 
    static Derived construct() { 
     Derived derived; 
     derived.hello(); 
     return derived; 
    } 

    protected: 
    Base() {}; 

    public: 
    virtual ~Base() {}; 

    public: 
    virtual void hello() = 0; 
}; 

class Derived : public Base 
{ 
    public: 
    virtual void hello() { 
     std::cout << "Hello\n"; 
    } 
}; 

int main() 
{ 
    Derived d = Base::construct<Derived>(); 
}