наследование — c ++ опасный код приведения

Я уверен, что это опасный код. Тем не менее, я хотел проверить, есть ли у кого-нибудь идея какие точно пойдет не так.

Предположим, у меня есть структура этого класса:

class A {
protected:
int a;
public:
A() { a = 0; }
int getA() { return a; }
void setA(int v) { a = v; }
};

class B: public A {
protected:
int b;
public:
B() { b = 0; }
};

И затем предположим, что я хочу иметь способ автоматического расширения класса следующим образом:

class Base {
public:
virtual ~Base() {}
};

template <typename T>
class Test: public T, public Base {};

Один действительно важная гарантия того, что я не могу дать Base ни Test будет иметь любые другие переменные-члены или методы. Это по сути пустые классы.

(Потенциально) опасный код ниже:

int main() {
B *b = new B();

// dangerous part?
// forcing Test<B> to point to to an address of type B
Test<B> *test = static_cast<Test<B> *>(b);

//
A *a = dynamic_cast<A *>(test);
a->setA(10);
std::cout << "result: " << a->getA() << std::endl;
}

Обоснование для того, чтобы сделать что-то вроде этого, заключается в том, что я использую класс, похожий на Test, но для того, чтобы он работал в настоящее время, обязательно нужно создать новый экземпляр T (т.е. Test), а также скопировать переданный экземпляр. Было бы здорово, если бы я мог просто указать Test на адрес памяти T.

Если бы Base не добавил виртуальный деструктор, а так как Test ничего не добавил, я бы подумал, что этот код на самом деле в порядке. Однако добавление виртуального деструктора заставляет меня беспокоиться, что информация о типе может быть добавлена ​​в класс. Если это так, то это может привести к нарушениям доступа к памяти.

Наконец, я могу сказать, что этот код отлично работает на моем компьютере / компиляторе (clang), хотя это, конечно, не является гарантией того, что он не делает плохих вещей с памятью и / или не потерпит неудачу на другом компиляторе / машине.

0

Решение

Виртуальный деструктор Base::~Base будет вызываться при удалении указателя. поскольку B не имеет надлежащего vtable (вообще нет в коде, размещенном здесь), который не очень хорошо закончится.

Это работает только в этом случае, потому что у вас есть утечка памяти, вы никогда не удаляете test,

5

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

Ваш код производит неопределенное поведение, так как он нарушает строгие псевдонимы. Даже если это не так, вы вызываете UB, поскольку ни B, ни A не являются полиморфными классами, а указанный объект не является полиморфным классом, поэтому dynamic_cast не может преуспеть. Вы пытаетесь получить доступ к базовому объекту, который не существует, чтобы определить тип среды выполнения при использовании dynamic_cast,

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

Это совсем не важно — это совершенно не имеет значения. Стандарт должен был бы поручить EBO, чтобы это даже начало иметь значение, а это не так.

1

Пока вы не выполняете никаких операций с Test<B>* и избегайте любой магии, такой как умные указатели или автоматическое управление памятью, все будет в порядке.

Вы должны обязательно искать скрытый код, такой как отладочные отпечатки или протоколирование, которые будут проверять объект. У меня произошел сбой отладчиков за попытку просмотреть значение указателя, установленного следующим образом. Держу пари, это причинит вам некоторую боль, но вы должны быть в состоянии заставить это работать.

Я думаю, что настоящая проблема заключается в обслуживании. Сколько времени пройдет, прежде чем какой-нибудь разработчик сделает операцию над Test<B>*?

-1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector