Защо редът на наследяване или картографирането засяга индекса на vftable? (за VSC за C++)

Когато си играя малко с полиморфизма, се опитах да направя нещо като следното:

class a { virtual void method() { } };
class b { virtual void method() { } };
class c : public a, b {
    virtual void method() { }
    virtual void anotherMethod() { } // (1)
};
class d : public c, a, b // (2)
{ virtual void method() { } }; // C2369

Доколкото знам, това трябва да работи без никакъв проблем. Но компилаторът казва: error C2369: 'const d::'vftable'{for 'a'}' : redefinition; different subscripts И нямам представа защо се случва това. Има три начина за разрешаване на тази грешка: Или методът (1) може да бъде премахнат, или редът на наследяване (2) може да бъде променен. Редактиране: Освен това прилагането на виртуално наследяване може да го реши. Така че изглежда, че редът на наследяване или картографирането засяга vftable. vftable е масив за съпоставяне на виртуални членски функции - известен още като. динамично обвързване в C++.

Затова разгледах и документация на Microsoft за C2369 където те показват това като пример, как да възпроизведете тази грешка:

int a[10];
int a[20];   // C2369
int b[20];   // OK

С други думи промяната на реда на наследяване променя индекса на тази таблица?! Някакви идеи?


person Christoph Meißner    schedule 02.07.2012    source източник
comment
Вероятно virtual наследство? en.wikipedia.org/wiki/Virtual_inheritance   -  person BoBTFish    schedule 02.07.2012
comment
Да, това също изглежда решава този проблем, ще го добавя към въпроса си. Но все още не разбирам защо това засяга индекса на vftable.   -  person Christoph Meißner    schedule 02.07.2012


Отговори (1)


Класовете наследяват частно по подразбиране (за разлика от структурите)! Следователно "c" наследява само публично от "a"! Липсва ви друга публична ключова дума:

class c : public a, public b

Друг проблем, с който се сблъсквате е, че наследявате от 2 класа, които дефинират една и съща член-функция. a::method не картографира към същия адрес като b::method! Следващият ви проблем вероятно ще бъде, че извикванията на "метод" са двусмислени...

person MFH    schedule 02.07.2012
comment
Да, разбира се, това беше случаят, който исках да проверя, докато си играех. И да, прав си, адресът на a::method не съответства на b::method. Но не трябва ли компилаторът да може да реши това? BTW: Добавянето на публичните модификатори не променя нищо в моите очи. - person Christoph Meißner; 02.07.2012
comment
Завършвате само с едно void method() в d. Вижте stackoverflow.com/questions/5545897/ (въпреки че цитира стария стандарт). - person BoBTFish; 02.07.2012
comment
Той не може да го разреши, защото тези две членски функции не са непременно еднакви! Ако компилаторът направи това, той ще наруши идеята за множествено наследяване на фундаментално ниво... - person MFH; 02.07.2012
comment
Това очаквах този пример да направи/покаже. И точно това е проблемът според мен. vftable трябва да съдържа този единствен метод, защото и двете декларации са заменени/скрити(?) в class d + допълнителния метод (2) на class c. - person Christoph Meißner; 02.07.2012