2015-04-02 3 views
1

Я столкнулся с ситуацией, где я бы хотел вызвать виртуальный метод из конструктора. Это, конечно, невозможно (или, по крайней мере, это не приводит к желаемому поведению). In this answer в качестве рабочего порядка предлагается использовать заводской метод. Я написал примерно следующее:Как скрыть конструктор при использовании фабрики?

#include <iostream> 
class Base { 
    public: 
     Base(){} 
     ~Base(){} 
    // private: ?? 
     virtual void afterConstruction()=0; 
}; 
class Derived : public Base { 
    public: 
     Derived() : Base() {} 
    //private: ?? 
     void afterConstruction(){std::cout<<"construct"<<std::endl;} 
}; 
template <typename T> T MyFactory(){ 
    T t = T(); 
    T* p = &t; 
    p->afterConstruction(); 
    return t; 
} 
int main(int argc, char** argv) { 
    Derived d = MyFactory<Derived>(); 
    return 0; 
} 

Это своего рода шаблон шаблона метода. Каждый производный класс может настроить способ его построения. Однако вся эта конструкция имеет смысл, когда пользователь этих классов не может напрямую вызвать конструктор или afterConstruction(). Поэтому я хотел бы, чтобы они были частными. Возможно, это глупый вопрос, и я просто не вижу очевидного. Возможно, я могу достичь этого, используя дружбу или что-то в этом роде, но я не уверен, что это лучший способ. Какой хороший и чистый способ скрыть эти два метода и разрешить создание объекта только с помощью фабричного метода?

EDIT: Ka7Im1011 Я понял, что на самом деле не совсем понятно, о чем я прошу. Таким образом, я попытаюсь прояснить:

Я хочу написать базовый класс, из которого придется вывести другие. Построение производных объектов связано со специфическими вещами, которые я хотел бы оставить вне базового класса. При поиске в Интернете для виртуального конструктора я нашел вышеупомянутый q & a, и я думаю, что заводский подход может работать хорошо. Тем не менее, я не знаю, как достичь следующих целей:

  • Необходимо создать экземпляры Derived с завода. В противном случае производный объект может быть создан в несогласованном состоянии. (Я полагаю, что только в базовом классе я не могу обеспечить это, но просить каждого кодера из Derived, чтобы сделать конструктор private/protected достаточным.)
  • Если возможно, Derived должен реализовывать только чистые виртуальные методы Base, потому что то писать производный вполне удобные (IDE/компиляторы точно сказать, что должно быть реализовано в противоположность громоздким, а иногда сообщения загадочная ошибка, когда, например, интерфейс параметра шаблона должен быть реализован)
+3

защищены, может быть? – MichaelCMS

+2

... и изготовление фабричного метода 'friend'. –

+0

Смотрите, мой ответ. добавьте комментарий, если вы застряли. –

ответ

1

Я не получу ваш вопрос точно, но вы можете его искать.

#include <iostream> 
#include <conio.h> 

class Base 
{ 
    virtual void afterConstruction() = 0; 
}; 
class Derived : Base { 
private: 
    Derived() : Base() {} 
public: 
    void afterConstruction(){ std::cout << "construct" << std::endl; } 
protected: 
    static Derived GetInstance() 
    { 
     return Derived(); 
    } 
}; 
template <class T> class MyFactory : T 
{ 
public: 
    static T GetInstance() 
    { 
     // Make sure every kind of T has protected GetInstance() 
     T t = T::GetInstance(); 
     T* p = &t; 
     p->afterConstruction(); 
     return t; 
    } 
}; 
int main(int argc, char** argv) { 
    Derived d = MyFactory<Derived>::GetInstance(); 
    // Derived d1; // will cause error 
    _getch(); 
    return 0; 
} 

Edited Ответ

#include <iostream> 
#include <conio.h> 

class Base 
{ 
protected: 
    Base() { } 
    virtual void afterConstruction() = 0; 
    virtual Base* GetInstance() = 0; 
}; 

class Derived : public Base { 
protected: 
    Derived() : Base() { } 
    void afterConstruction() 
    { 
     static bool bConstrucred = false; 
     if (!bConstrucred) 
     { 
      std::cout << "construct" << std::endl; 
      bConstrucred = true; 
     } 
    } 
    Derived* GetInstance() 
    { 
     afterConstruction(); 
     return this; 
    } 
}; 

template <class T> class MyFactory : public T 
{ 
public: 
    T* GetInstance() { return T::GetInstance(); } 
}; 

int main(int argc, char** argv) { 
    Derived* d = MyFactory<Derived>().GetInstance(); 
    // Derived d1; // will cause error 
    _getch(); 
    return 0; 
} 
+0

Да, возможно, я не был достаточно ясен, когда задавал вопрос. Что мне нравится в шаблоне метода шаблона, так это то, что производному классу нужно только реализовать чистые виртуальные методы для работы, как ожидалось. С помощью этого решения каждый класс Derived должен реализовать GetInstance (который не может быть виртуальным, поскольку его статический). Но, может быть, я просто это переусердствую. В любом случае, делая это так, любой, кто пишет производный класс, не имеет никакого шанса создать объект этого класса, который не ведет себя так, как ожидалось (и компилятор скажет ему, чего не хватает, если он забыл реализовать «GetInstance»). – user463035818

+0

ОК, во-первых, я понял, что 'Derived class не может иметь собственный метод, кроме виртуального метода Base class'. но я все еще смущен тем, что вы хотите разрешить пользователю создавать объект класса Derived с использованием конструктора по умолчанию или нет? '. –

+0

нет, это не должно быть возможно. Я отредактирую вопрос, чтобы сделать его более ясным. – user463035818

0

Я не хочу испортить мой вопрос, таким образом, я отправляю свое (частичное) решение в качестве ответа ...

#include <cstdlib> 
#include <iostream> 
using namespace std; 

class Base { 
    public: 
     ~Base(){} 
     template <typename T> static T BaseFactory(){ 
      T t = T(); 
      Base* p = &t; 
      p->afterConstruction(); 
      return t; 
     } 
    protected: 
     Base(){} 
    private: 
     virtual void afterConstruction()=0; 
}; 

class Derived : public Base { 
    private: 
     void afterConstruction(){std::cout<<"construct"<<std::endl;} 
}; 
int main(int argc, char** argv) { 
    Derived d = Base::BaseFactory<Derived>(); 
    return 0; 
} 

Я до сих пор не знаю, как сделать производные конструкторы частными/защищенными. Я хотел бы избегать друзей, потому что (как я понимаю) каждый раз, когда добавляется производный класс, мне нужно будет изменить базу.