C ++ dynamic_ptr_cast для shared_ptr из базы в производные сбои - PullRequest
4 голосов
/ 26 января 2012

Это загадка, с которой я столкнулся на этой неделе.Отчасти это связано с тем, что я только что вернулся к кодированию на C ++ после некоторого программирования на Java.Учитывая следующий код:

class Base {
};

class A : Base {
public:
    virtual void run() { cout << "This is A." << endl; }
};
class B : Base {
public:
   virtual void run() { cout << "This is B." << endl; }
};

class C : A, B {
public:
   void run() { cout << "This is C." << endl; }
};

int main(int argc, char* argv[])
{
   shared_ptr<A> ptrToA = shared_ptr<C>(new C());

   cout << "Pointer to A: " << ptrToA.get() << endl;
   cout << "Dynamic Cast A ptr to C: " << dynamic_pointer_cast<C>(ptrToA) << endl;

   ptrToA->run();

   assert(dynamic_pointer_cast<C>(ptrToA));
   cout << "Success!" << endl;
}

Почему он выдает следующий вывод?

Pointer to A: 0x1f29c010
Dynamic Cast A ptr to C: 0
Running...
This is C.
tester-cpp: tester.cpp:89: int main(int, char **): Assertion `dynamic_pointer_cast<C>(ptrToA)' failed.

Поскольку выводится "This is C", очевидно, что полиморфизм работает, но онне удается при динамическом приведении shared_ptr из базового класса «A» в «C».Я потратил впустую часы на этот тонкий вопрос на этой неделе!Надеемся, что любые ответы помогут будущим кодировщикам с похожей проблемой сэкономить много времени (ошибка была очень незначительной, особенно после некоторого времени написания кода на Java).

Почему?(Я дам вам подсказку ... этот код был скомпилирован с помощью компилятора Intel C ++ 12.1.0 в Linux. Я попробовал его с другим компилятором, и мой код не компилируется! )

1 Ответ

7 голосов
/ 26 января 2012

Тот факт, что он не может быть скомпилирован на другом компиляторе, является подсказкой: он действительно должен не скомпилироваться. Это связано с тем, что C в частном порядке наследуется от A и B, поэтому C* не должно быть преобразовано в A*. Поэтому shared_ptr<A> ptrToA = shared_ptr<C>(new C()); не должен компилироваться, так как конструктор диалога должен участвовать в разрешении перегрузки только тогда, когда указатель может быть преобразован в соответствии со стандартом. Так что это похоже на ошибку в стандартной библиотеке, используемой Intel C ++.

Измените Class C: A, B на Class C: public A, public B, и оно должно работать. При тестировании на gcc 4.6 код действительно не компилируется с частным наследованием и работает так же, как и при публичном наследовании A.

Поскольку ваш код содержит алмазное наследование , вы также можете взглянуть на виртуальное наследование .

...