Почему эта простая иерархия классов C ++ не проявляет полиморфное поведение? - PullRequest
1 голос
/ 17 ноября 2010

Буду признателен, если кто-нибудь расскажет мне о следующем поведении - я запечатлел это на коротком примере кода:

//header.h

class base
{
public:
 base(int data):data1(data){}
 virtual int getData(){return data1;}
private:
 int data1;
};

class derived1 :public base
{
public:
 derived1(int data):base(data-1),data2(data){}
 virtual int getData(){return data2;}
private:
 int data2;
};

class derived2 :public derived1
{
public:
 derived2(int data):derived1(data-1),data3(data){}
 virtual int getData(){return data3;}
private:
 int data3;
};


//main.cpp

derived1 d1(20);
derived2 d2(10);

base& baseRefd1 = d1, baseRefd2 = d2; 

cout << "call to baseRefd1.getData() yields: " << baseRefd1.getData();
cout << "call to baseRefd2.getData() yields: " << baseRefd2.getData();

derived1& derived1Refd1 = d1, derived1Refd2 = d2; 

cout << "call to derived1Refd1.getData() yields: " << derived1Refd1.getData();
cout << "call to derived1Refd2.getData() yields: " << derived1Refd2.getData();

И вывод:

call to baseRefd1.getData() yields: 20  
call to baseRefd2.getData() yields: 8  

call to derived1Refd1.getData() yields: 20  
call to derived1Refd2.getData() yields: 9  

Как вы можете видеть, когда базовая ссылка используется в качестве дескриптора одного уровня деривации, мы получаем полиморфизм - вызываемая версия getData () - это версия производного класса.

Но когда одна и та же базовая ссылка используется в качестве дескриптора для класса, выведенного на 2 уровня в иерархии, полиморфизм отсутствует - называется версия getData, которая называется базовой.

Когда используется ссылка типа производного1, т. Е. Среднего уровня иерархии, полиморфизм отсутствует, даже когда дескриптор указывает на уровень класса 1.

Я уверен, что мне нужно научиться чему-то основному здесь. Буду признателен за любые рекомендации.

Ответы [ 3 ]

13 голосов
/ 17 ноября 2010
base& baseRefd1 = d1, baseRefd2 = d2;  

Это то же самое, что и

base& baseRefd1 = d1;
base  baseRefd2 = d2;  
    ^ baseRefd2 is not a reference!

Вам нужен еще один амперсанд:

base& baseRefd1 = d1, & baseRefd2 = d2;  
                      ^ this makes baseRefd2 a reference

Это одна из лучших причин следовать правилу «объявляйте только одну переменную за раз, особенно при объявлении указателей или ссылок».

3 голосов
/ 17 ноября 2010

На самом деле можно объявить несколько ссылок без повторения символа &:

template <typename T>
struct reference_to
{
    typedef T & type;
};

reference_to<base>::type baseRefd1 = d1, baseRefd2 = d2;
1 голос
/ 17 ноября 2010

baseRefd2 и производный1Refd2 не являются ссылками, они являются копиями.

виновато объявление вашей переменной.То, что вы написали, если разделить на 2 строки, выглядит так:

base& baseRefd1 = d1;
base baseRefd2 = d2;

и

derived1& derived1Refd1 = d1;
derived derived1Refd2 = d2;

(ПРИМЕЧАНИЕ: отсутствие усилителя на 2-м объявлении в каждой)

правильноеспособ объявить их в одной строке:

base& baseRefd1 = d1, &baseRefd2 = d2;   

derived1& derived1Refd1 = d1, &derived1Refd2 = d2; 

(обратите внимание на новые амперсанды)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...