2015-07-01 2 views
2

Я вижу совсем другое поведение в том, как C++ и Python обрабатывают сценарий наследования алмазов.Решение множественного разрешения наследования: C++ vs Python

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

Python печатает "BB"

class A(object): 
    def foo(self): 
     print 'A' 

class B(A): 
    def foo(self): 
     print 'B' 
    def bar(self): 
     self.foo() 

class C(A): 
    def foo(self): 
     print 'C' 
    def bar(self): 
     self.foo() 

class D(B, C): 
    def bar(self): 
     B.bar(self) 
     C.bar(self) 

D().bar() 

Но C++ печатает "BC"

struct A 
{ 
    virtual void foo() { 
     cout << "A" << endl; 
    } 
}; 

struct B : public A 
{ 
    virtual void foo() { 
     cout << "B" << endl; 
    } 

    virtual void bar() { this->foo(); } 
}; 

struct C : public A 
{ 
    virtual void foo() { 
     cout << "C" << endl; 
    } 

    virtual void bar() { this->foo(); } 
}; 

struct D : public B, public C 
{ 
    virtual void bar() { 
     B::bar(); 
     C::bar(); 
    } 
}; 

int main() 
{ 
    D().bar(); 
} 

Когда я добавить строку cout << typeid(*this).name() << endl; к каждому bar() описанным выше способом в C++, это то, что печатается :

B 0x7fff803d9b70 
C 0x7fff803d9b78 
D 0x7fff803d9b70 

Похоже, что B и D поделились тем же адресом, но C находится в другой таблице vtable.

Редактировать

Как указывается в ответе @JoranBeasley, я попытался следующие проверки кода Python:

D.foo == B.foo 
D.foo == C.foo 
D.foo is B.foo 
D.foo is C.foo 

Python 2.7 распечатывает True False False False

Python 3.4 распечатывает True False True False

Кажется, что и B.foo и D.foo - один и тот же метод по значению как в python 2, так и 3, но python 2 делает копию, а python 3 - нет.

+0

Если вы хотите питона, как наследование в C++, вам нужно использовать виртуальное наследование. – o11c

+1

Этот C++ не настоящий алмаз: 'D' имеет 2 разных унаследованных' A' баз. – rodrigo

+0

@ o11c: Я действительно хочу наоборот: поведение на C++ является предпочтительным. –

ответ

3

Я могу только объяснить питона биты ...

C.bar(self)

передает экземпляр D, который вы создали в качестве self

поэтому, когда он называет self.foo() это ничем не отличается, чем если вы сказал, что self.foo() внутри D.bar (т.е. self остается статически одинаковым)

Поскольку наследование выполнено Право на L EFT B.foo тени C.foo

D.foo is B.foo # should print True 
D.foo is C.foo # should print false 

вы могли бы грубой всегда называют

C.foo(self) #prints C as expected 

это на самом деле не имеет ничего общего с Python множественным разрешением порядка методом наследования, так что обрабатывается с super() вызова ... вместо вас пытаются явно вызвать ваши методы родительского класса, вместо того, чтобы позволить python разрешать их для вас неявно

насколько он отличается от C++, его becaus e это два отдельных языка, которые реализовали наследование и множественное наследование различными способами ...

как упомянуто в комментариях вы можете изменить определение двойки к

class D(C,B): 
    ... 

затем D().foo() напечатает C

+1

Также упоминайте, что если он изменяет порядок наследования ('class D (B, C):') на ('class D (C, B):') он будет печатать 'CC';) (после того, как вы объяснили наследование справа налево) –

+0

Спасибо за ответ. Но обе строки печатают «False». –

+0

@JimJarvis Не могли бы вы упомянуть версию Python? –

Смежные вопросы