Допустим, у меня есть абстрактный класс, который дорого создавать и копировать:
class AbstractBase {
public:
AbstractBase() {
for (int i = 0; i < 50000000; ++i) {
values.push_back(i);
}
}
virtual void doThing() = 0;
private:
vector<int> values;
};
Он имеет два подкласса FirstDerived
:
class FirstDerived : public AbstractBase {
public:
void doThing() {
std::cout << "I did the thing in FirstDerived!\n";
}
};
и SecondDerived
:
class SecondDerived : public AbstractBase {
public:
void doThing() {
std::cout << "I did the thing in SecondDerived!\n";
}
};
Кроме того, я хотел бы создать класс, который использует FirstDerived
или SecondDerived
, используя композицию (а не агрегацию). Это означает, что я хочу, чтобы ComposedOfAbstractBase
владел любым переданным временным файлом. Если бы я не использовал абстрактные классы, этот класс выглядел бы так: (в С++ 11)
class ComposedOfWhicheverDerived {
public:
ComposedOfWhicheverDerived(AbstractBase abstract_base) : abstract_base(std::move(abstract_base)) {;}
private:
AbstractBase abstract_base;
};
Однако это не работает с абстрактными классами, потому что я никогда не смогу создать экземпляр AbstractBase
, даже если буду остерегаться передачи временного AbstractBase
, например:
ComposedOfWhicheverDerived a(FirstDerived());
Для компилятора это так же плохо, как:
ComposedOfWhicheverDerived b(AbstractBase());
Потому что у меня все еще есть экземпляр AbstractBase
в объявлении класса.
Следующее решение, которое я придумал, это:
class ComposedOfAbstractBase {
public:
ComposedOfAbstractBase(AbstractBase&& abstract_base) : some_derived_instance(abstract_base) {;}
private:
AbstractBase& some_derived_instance;
};
Это работает отлично (хотя я не совсем понимаю)! Оба эти экземпляра действительны и работают по назначению:
ComposedOfAbstractBase a(FirstDerived());
ComposedOfAbstractBase b(SecondDerived());
Он не создает копию любого переданного временного AbstractBase
, и разрешено хранить ссылку на AbstractBase
. Хотя в лучшем случае ссылка на ссылку rvalue кажется неясной: она не означает, что ComposedOfAbstractBase
владеет каким бы временным параметром ни было передано. Кроме того, оказывается, что это решение кажется неоптимальным. Чтобы показать это, я создал этот класс:
class ComposedOfFirstDerived {
public:
ComposedOfFirstDerived(FirstDerived first_derived) : first_derived(std::move(first_derived)) {;}
private:
FirstDerived first_derived;
};
Который может принимать только FirstDerived
, поэтому мы можем применить std::move
, чтобы разгрузить временное владение. Я могу сделать такой экземпляр:
ComposedOfFirstDerived c(FirstDerived());
Интересно, что этот класс постоянно создается на 10% быстрее, чем ComposedOfAbstractClass
.
Кто-нибудь знает, что здесь происходит? Почему ComposedOfFirstDerived
создается намного быстрее, чем ComposedOfAbstractBase
? Есть ли лучший способ сделать композицию с абстрактными классами, или я застрял с неоптимальным решением?
Извините, если это был вопрос с полным ртом. Я ценю любого, кто найдет время, чтобы прочитать его и дать искренний ответ, потому что я вне тупика!