2014-01-14 4 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; 
} 

Этот код явно не запускается (хотя он компилируется с предупреждениями на некоторых компиляторах). Вопрос в том, каков наилучший способ реализации такого рода шаблонов? Предполагая, что в базе существуют десятки производных классов и десятки конструкторов, переопределение базовых конструкторов в производном классе (с вызовами базовых конструкторов и 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: Да и нет. Конструктор шаблонов никогда не является конструктором копирования или перемещения, поэтому pass-by-value не будет использовать шаблон. Но когда вы вызываете конструктор напрямую, вы можете получить нежелательный. См. 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>(); 
} 
Смежные вопросы