О множественном наследовании и определении виртуальной функции - PullRequest
13 голосов
/ 06 мая 2011

У меня есть сценарий множественного наследования без виртуальных базовых классов, подобный этому:

 Ta  Tb
 |   |
 B   C
  \ /
   A

Ta и Tb - это два разных шаблонных класса, которые оба объявляют виртуальную функцию с именем f (). Я хочу переопределить две функции в области A, потому что мне нужно взаимодействовать с данными B и C в этих методах. Но я не знаю, как это сделать.

class Tb {
protected:
    virtual void f() {};
public:
    void call() {
        this->f();
    };  
};

class Tc {
protected:
    virtual void f() {};
public:
    void call() {
        this->f();
    };
};

class B : public Tb {
public:
    void doSomething() {};
};

class C : public Tc {
private:
    int c;
public:
    void inc() { c++; };
};

class A : public B, public C {
protected:
    void f() { // this is legal but I don't want to override both with the same definition.
        // code here
    }
    // if Tb::f() is called then i want to call C::inc()
    // if Tc::f() is called then i want to call B::doSomething()
public:
    void call() {
        B::call();
        C::call();
    };
};

Существует ли синтаксис для переопределения обоих методов с разными определениями, или я должен определить их в B и C?

Спасибо

Edit: Моя проблема не в том, что нельзя вызывать Tb :: f () или Tc :: f (), а в том, что я хочу определить два разных поведения, если вызывается Tb :: f () или Tc :: f (). Эти методы вызываются Tb и самим Tc в своих открытых методах. Модифицированный пример, так что, может быть, более понятно, что я хочу сделать ...

Ответы [ 3 ]

7 голосов
/ 06 мая 2011

Есть ли синтаксис для переопределения обоих методов с разными определениями или мне нужно определить их в B и C?

Краткий ответ: нет.

Ваш A:f() будет переопределять как Ta::f(), так и Tb::f().

. Если вам нужны разные переопределения, единственное решение - вставить вспомогательные классы Hb и Hc:

Ta  Tb
|   |
B   C
|   |
Hb  Hc
 \ /
  A 

Hb может быть как две функции, просто переименовать функцию:

class Hb: public B {
   protected: // overrides from Ta
     virtual void f() { Ta_f(); }

   protected: // new virtuals
     virtual void Ta_f() = 0;
 };

, а затем вы можете определить A::Ta_f(), чтобы делать все, что вы хотите (включая вызов B::f()!)

3 голосов
/ 06 мая 2011

Вы обязательно должны иметь возможность заменить A на Tb или Tc?Если нет, то рассматривали ли вы возможность использования композиции в A вместо наследования?

Если вам нужно заменить таким образом, не задумывались ли вы о том, чтобы взять простой способ и просто назвать родительские методы двумя разными именами?Поскольку вы хотите переопределить их по отдельности, это означает, что они не делают одно и то же.

3 голосов
/ 06 мая 2011

Вы переопределили оба в классе A. Если бы вы этого не сделали, была бы двусмысленность, если бы директива using не использовалась, чтобы явно указать, какой метод из тех, которые вы предпочитаете.

Вы можете переопределить эти методы отдельно в классах B и C, но опять же, как только класс A наследует оба, вы должны решить, какой из них следует использовать.

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