наследование — расширение существующего класса C ++

Я хотел бы добавить дополнительную функциональность без изменения существующего класса.

Сказать,

class base{
public:
int i;
base(){i = 1;}
virtual void do_work(){ //Do some work}
};

Если я хочу добавить serialization функция-член к нему, я просто создаю производный класс

class derived:public base{
public:
void serialize();
};

void derived::serialize(){
cout << "derived class" << endl;
}

И мне нужно справиться с существующими base объекты, например.

int main(){
base a;
derived & b = static_cast<derived &>(a);

b.serialize();
}

Этот пример работает без проблем. Но я знаю downcast через static_cast это то, чего следует избегать в целом.

Но я хотел бы знать, если downcast для этого конкретного случая использования можно считать безопасным, так как derived класс имеет только одну дополнительную функцию-член. Будет ли у него какое-то потенциально неопределенное поведение для доступа vtable?

3

Решение

Если вы можете написать функцию сериализации в производном классе, не затрагивая закрытые или защищенные члены, тогда вы просто должны сделать ее свободной функцией. Это решает все.

2

Другие решения

То, как вы расширяете Base вы не используете vtable потому что у тебя нет virtual методы. Может быть проще думать об этом как Derived has A Base; Что вы создали новый класс, который содержит Base переменная-член.

Мое предложение.

Функция шаблона

Я лично пошел бы с шаблонной функцией. Вы можете сохранить всю работу в своем первоначальном вопросе, и избежать необходимости добавления virtual звонки в ваш класс.

template<typename T>
void serialize_object(T& t)
{
t.serialize()
}

А потом по вашему примеру.

Derivied d;
serialize_object(d);

Большим преимуществом является то, что вы не добавляете приведение во время исполнения здесь. Компилятор сообщит вам, если вы передадите объект, у которого нет метода serialize,

Go Virtual

Если вы действительно хотите справиться с этим через виртуальный интерфейс, сделайте это.

struct Serializable{
virtual void serialize()=0;
virtual ~Serializable(){}
}

class Derived : public Serializable {
public:
void serialize() override;
}

void Derivied::serialize()
{
std::cout << "Yah\n";
}

Тогда в вашем коде.

Derivied d;
Serializable& s = dynamic_cast<Serializable&>(d);

Тем не менее, большая проблема заключается в том, кто является владельцем вашего базового класса? Они предоставили виртуальный дтор? Если нет, то используя std::unique_ptr или же std::shared_ptr может заставить вас не иметь дело напрямую с интерфейсом.

1

Вы не можете просто привести объект базового класса к унаследованному классу. Любые члены в унаследованном классе не будут созданы и инициализированы. Вам нужно начать с объекта унаследованного класса.

Конечно, вы можете пойти другим путем и вызвать функции базового класса из функции класса, унаследованного от базового, потому что объект базового класса всегда будет присутствовать как часть наследуемого объекта класса, по определению.

Если у вас есть указатель на базовый класс, и вы строите с помощью RTTI, вы можете использовать dynamic_cast для приведения к унаследованному классу, но это приведение завершится неудачно и вернет NULL, если объект не принадлежит к классу, который вы пытаетесь привести к , Но обычно лучше вызывать виртуальную функцию, чем использовать dynamic_cast.

0
По вопросам рекламы [email protected]