2013-07-21 2 views
1

Это вопрос Python и C++.Множественное наследование в python vs C++

Я экспериментирую с множественной наследственностью, и я столкнулся с этим примером.

B1 B2 
\/
    D 

Скажем, у меня есть два независимых (?) Родительские классы класса B1, B2 и один ребенок D. Объекты размером class D.

class B1: 
    def f1(self): 
     print "In f1" 

class B2: 
    def f2(self): 
     self.f1() 

class D (B1, B2): 
    def fD(self): 
     self.f2() 

d = D() 
d.fD() 

Output: In f1 

Что интересно (по крайней мере для меня), что class B2 не имеет знаний о class B1 и еще f2 можно назвать self.f1() без проблем.

Я попытался воспроизвести эту точную вещь на C++, и я не смог заставить ее работать, потому что я не знаю, как позвонить f1 из f2.

class B1 { 
    public: 
    virtual ~B1() {} 
    virtual void f1() { cout << "In f1" << endl; } 
}; 

class B2 { 
    public: 
    virtual ~B2() {} 
    virtual void f2() { /* What goes here?? */ } 
}; 

class D : public B1, public B2 { 
    public: 
    void fD() { f2(); } 
}; 

Итак, я хочу знать, как/почему Python может справиться с этим, но C++ не может?

Кроме того, какие минимальные изменения мы можем внести в код на C++, чтобы заставить его вести себя как код Python?

+3

Это не очень интересно в Python. Он просто пытается (динамически) разрешить данное свойство с помощью дерева MRO (Order Resolution Order) (это немного сложнее, чем просто искать свойство благодаря всем различным правилам, но это о том, как его можно суммировать). Дерево MR (Разрешение метода) * всегда * начинается с приемника, который является экземпляром текущего объекта, когда используется self - это также то, как Python позволяет переопределять и полиморфизм, а не определяющий тип метода. Чтобы вызвать метод для определенного типа, см. 'TheType.method (self, ..)' – user2246674

+0

@ user2246674: Это правда, когда классы не являются «новым стилем» (т. Е. Производным от 'object')? Если это важно, ответ должен быть отредактирован. –

ответ

1

Какие минимальные изменения мы можем внести в код C++, чтобы заставить его вести себя как код Python?

Короткий ответ: Вы не можете. B2 не имеет понятия, что он станет частью подкласса, который также имеет B1 как суперкласс.

Длинный ответ: Вы можете, если вы используете какой-то безобразный понижающее приведение (по существу, литье this к D*). Но это, вероятно, не очень хорошая идея, так как *this не обязательно D.

0

Я хочу знать, как/почему Python может справиться с этим, но C++ не может?

Это потому, что Python динамически типизирован и C++ статически типизирован.

Какие минимальные изменения мы можем внести в код C++, чтобы заставить его вести себя как код Python?

Если вы хотите запрограммировать программу на Python, вы знаете, где ее найти. Программирование на C++ с использованием способов Python противоречит идиоматике и, как правило, неодобрительно. Тем не менее, если вы все равно хотите это сделать, вы используете dynamic_cast<B2*>(this).

1

Это работает в python, потому что имя f1 в классе B2 разрешается во время выполнения. Это «duck typing» - ссылка на объект в self должна иметь действительный f1 для вызова, который он делает при его построении таким образом.

Самый C++ - подобный способ получить аналогичное поведение в C++ - это Curiously recurring template pattern.Ваша версия C++ B2 должна знать, в чем она заключается. Создание шаблона его производного типа дает вам «чистый» способ сделать dynamic_cast, который другие предложили. Это чище, потому что для каждого класса, который вытекает из него, будет новый класс B2<T>. Каждая специализация будет иметь вид f2, который использует правый бросок, чтобы попасть вправо f1. Он будет работать так же, как и версия python, поскольку существование вызываемого f1 - это все, что требуется (хотя время компиляции, а не время выполнения).

class B1 { 
    public: 
    virtual ~B1() {} 
    virtual void f1() { cout << "In f1" << endl; } 
}; 

template <typename Derived> 
class B2 { 
    public: 
    virtual ~B2() {} 
    virtual void f2() { dynamic_cast<Derived *>(this)->f1(); } 
}; 

class D : public B1, public B2<D> { 
    public: 
    void fD() { f2(); } 
}; 
Смежные вопросы