#c
#c
Вопрос:
Как в C создать класс, члены которого являются типами, имеющими расширения? Возьмем пример car. У нас есть a Car
и a BigCar
. В Car
комплекте идет an Engine
, но BigCar
должно быть a BigEngine
. Но если мы просто скроем engine
элемент BigCar
with BigEngine
, regular Engine
все равно будет создан и может сделать что-то во время построения, чего мы не хотим. Есть ли лучший способ? Или это единственный способ «ничего не делать во время построения». Я знаю, что мы могли бы использовать DIC, но я думаю, что есть действительно очевидный способ, о котором я не думаю…
Пример
#include <iostream>
class Engine {
public:
Engine() {
this->cylinders = 4;
}
virtual ~Engine() {}
int cylinders;
};
class BigEngine : public Engine {
public:
BigEngine():Engine() {
this->cylinders = 8;
this->fuel_injector = true;
}
bool fuel_injector;
};
class Car {
public:
Car() {
std::cout << this->engine.cylinders;
}
virtual ~Car(){ }
Engine engine;
};
class BigCar : public Car {
public:
BigCar():Car() {
std::cout << this->engine.fuel_injector;
}
~BigCar() { }
BigEngine engine;
};
int main()
{
BigCar car; // SHOULD print 81 but prints 41
}
Ответ №1:
С помощью шаблона:
#include <iostream>
class Engine {
public:
Engine() : cylinders{4} {}
int cylinders;
};
class BigEngine : public Engine {
public:
BigEngine() : Engine{}, fuel_injector{true} {
this->cylinders = 8;
}
bool fuel_injector;
};
template<typename E = Engine>
class Car {
public:
Car() {
std::cout << this->engine.cylinders;
}
E engine;
};
class BigCar : public Car<BigEngine> {
public:
BigCar(): Car<BigEngine>{} {
std::cout << this->engine.fuel_injector;
}
};
int main()
{
BigCar car;
}
Однако проблема заключается в том, что не будет одного отдельного Car
класса. Тем не менее, если вы хотите хранить разные типы движков в Car
(типы с разными размерами), вам нужно вместо этого хранить указатели. Например:
#include <iostream>
#include <memory>
class Engine {
public:
Engine() : cylinders{4} {}
int cylinders;
};
class BigEngine : public Engine {
public:
BigEngine() : Engine{}, fuel_injector{true} {
this->cylinders = 8;
}
bool fuel_injector;
};
class Car {
public:
Car() : Car{std::make_unique<Engine>()} {
}
std::unique_ptr<Engine> engine;
protected:
Car(std::unique_ptr<Engine> engine) : engine{std::move(engine)} {
std::cout << this->engine->cylinders;
}
};
class BigCar : public Car {
public:
BigCar(): Car{std::make_unique<BigEngine>()} {
std::cout << static_cast<BigEngine*>(this->engine.get())->fuel_injector;
}
};
int main()
{
BigCar car;
}
Ответ №2:
Ваш Car
класс может иметь указатель на Engine
, и соответствующий механизм может быть создан в constructo . Это позаботится о разных типах движков, когда вам придется добавлять электрические 🙂