Хотелось бы узнать, почему не совпадает мнения у Visual C++ 7 с остальными компиляторами?
А именно, для MS Visual C++ 7
m_c->n::A::Number(); не эквивалентно
((n::A*)m_c)->Number(); в приведённом ниже примере. В результате выполнения строки кода
m_c->n::A::Number(); вместо вызова виртуального метода родителя происходит вызов неизвестно чего. Зайдя в дебагере во внутрь этого вызова, видим что указател
this смещён на 4 байта.
Избежать проблему можно несколькими способами, но хочу понять именно эту ситуацию.
Варианты правок, чтобы код работал правильно:
— Отказаться от
namespace
— В классе
I сделать функцию
foo() невиртуальной
— При объявлении класса
C поменять порядок родительских классов (класс
I поставить последним)
— Заменить вызов
m_c->n::A::Number(); на
((n::A*)m_c)->Number();
А чтобы вообще получить
access violation нужно в исходном примере добавить в класс
I член класса (например
int i;).
Уважаемые, объясните пожалуйста, как Visual C++ понимает такой вызов? Что он пытается сделать?
#include <iostream>
using namespace std;
namespace n
{
class A
{
public:
void Number() const
{
A_Number();
};
private:
virtual void A_Number() const = 0;
};
class B
{
public:
void Number() const
{
B_Number();
};
private:
virtual void B_Number() const = 0;
};
}
class I
{
public:
virtual void foo()
{
}
};
class C : public I, public n::A, public n::B
{
private:
virtual void A_Number() const
{
cout << "C::A_Number";
};
virtual void B_Number() const
{
cout << "C::B_Number";
};
};
class D: public n::A, public n::B
{
public:
D()
{
m_c = new C;
};
~D()
{
delete m_c;
m_c = NULL;
};
private:
C* m_c;
virtual void A_Number() const
{
cout << "D::A_Number -> ";
m_c->n::A::Number(); // only ((n::A*)m_c)->Number(); work ok!
cout << endl;
}
virtual void B_Number() const
{
cout << "D::B_Number -> ";
m_c->n::B::Number(); // only ((n::B*)m_c)->Number(); work ok!
cout << endl;
}
};
int main()
{
D d;
d.n::A::Number();
d.n::B::Number();
return 0;
}