Я столкнулся с ситуацией, когда я хотел бы вызвать виртуальный метод из конструктора. Это, конечно, невозможно (или, по крайней мере, не дает желаемого поведения). В этом ответе В качестве обходного пути предлагается использовать фабричный метод. Я написал что-то вроде этого:
#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()
непосредственно. Поэтому я хотел бы, чтобы они оба были приватными. Может быть, это глупый вопрос, и я просто не вижу очевидного. Может быть, я могу достичь этого, используя дружбу или что-то в этом роде, но я не уверен, что это лучший способ. Какой хороший и чистый способ скрыть эти два метода и разрешить создание объекта только методом фабрики?
РЕДАКТИРОВАТЬ:
Ka7Im1011 заставил меня понять, что не совсем понятно, о чем я прошу. Таким образом я постараюсь уточнить:
Я хочу написать базовый класс, который должен будет получить другой. Построение производных объектов включает в себя довольно специфические вещи, которые я бы хотел исключить из базового класса. При поиске в Интернете виртуального конструктора я обнаружил вышеупомянутую q&и я думаю, что фабричный подход мог бы работать хорошо. Однако я не уверен, как добиться следующего:
Я не совсем понимаю ваш вопрос, но, возможно, вы ищете это.
#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;
}
Отредактированный ответ
#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;
}
Я не хочу портить свой вопрос, поэтому я публикую свое (частичное) решение как ответ …
#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;
}
Я до сих пор не знаю, как сделать производные конструкторы частными / защищенными. Я хотел бы избегать друзей, потому что (насколько я понимаю) каждый раз, когда добавляется производный класс, мне придется менять базу.