2015-05-22 10 views
1
#include <iostream> 

using namespace std; 

class Base1 { 
public: 
    virtual void f(int n) = 0; 
}; 

class Base2 { 
public: 
    virtual void f(char *s) = 0; 
}; 

class Derive1 : public Base1, public Base2 { 
public: 
    void f(int n) { cout << "d1 fn" << endl; } 
    void f(char *s) { cout << "d1 fs" << endl; } 
}; 

class Derive2 : public Derive1 { 
public: 
    void f(int n) { cout << "d2 fn" << endl; } 
    void f(char *s) { cout << "d2 fs" << endl; } 
}; 

int main() { 
    Derive1 *d1 = new Derive2(); 
    int n = 0; 
    char *s = ""; 
    d1->f(n); 
    d1->f(s); 
    return 0; 
} 

Вышеприведенный код работает так, как ожидалось, но если я прокомментирую один метод Derive1, я получил ошибку преобразования; если я прокомментирую оба метода Derive1, у меня возникла ошибка неоднозначности методов.Перегрузка метода множественного наследования C++

Что меня смущает, почему Derive1 должен определить эти два метода, почему их определение только в Derive2 не работает. Мне нужна помощь, чтобы понять это.

Некоторые пояснения:

  1. Давайте предположим, что я никогда не хочу, чтобы создавать экземпляры Derive1. Таким образом, это вполне нормально, если Derive1 является абстрактным классом.

  2. «Все чистые виртуальные функции должны иметь определение в производном классе». Это неверно, если я не хочу создавать экземпляры этого производного класса.

  3. Если я изменю f в Base1 на f1 и f в Base2 на f2 (просто измените имена), то Derive1 не обязательно будет определять какие-либо из них, просто определите f1 и f2 в Derive2.

Так, при поддержке перегрузки методы, я думал, в приведенной выше коде, я объявил функцию с именем, как f_int в Base1; в Base2 я объявил функцию с именем, как f_str. Это способ, которым компилятор реализует перегрузку метода, не так ли? Но похоже, что это не так.

ответ

0

Derive1 - производный класс от Base1 и Base2. Производные классы must реализовать все чистый виртуальные функции их базовых классов.

Это не помогает Derive1, что Derive2 реализует эти функции, поскольку возможно создать экземпляр Derive1, и для этого он должен реализовать все наследуемые чистые виртуальные методы.

Например, если вы не реализовали функции в Derive1, что бы вы ожидали от этого поведения?

Derive1* d1 = new Derive1; 
int n = 0; 
char *s = ""; 
d1->f(n); 
d1->f(s); 

Derive1 не реализовывали их, и d1 не Derive2 экземпляр, так что же он должен делать?

+0

Производные классы должны реализовывать все ** чистые ** виртуальные функции. –

+1

Спасибо, я добавил это разъяснение к своему сообщению. – CoryKramer

+1

* Конкретные * классы должны реализовывать все чистые виртуальные методы из своего базового класса. Промежуточный абстрактный класс не нужен. Это не проблема в этом случае. –

0

Если вы объявите чистую виртуальную функцию в классе, она превратится в абстрактный класс, и вы не сможете ее создать. И все чистые виртуальные функции должны иметь определение в производном классе. Оба базовых класса имеют чистые виртуальные функции, поэтому ваш производный 1 должен определять чистые виртуальные функции базовых классов.

0

Давайте начнем с удалением как в Derived1:

Когда вы звоните d1->f, вы не создали какой-либо специально для этого класса, поэтому он смотрит на своих базовых классов. Каждый базовый класс будет рассматриваться как отдельный набор кандидатов. Поэтому сначала он проверяет base1 и видит f, затем проверяет base2 и видит еще f. Компилятор не может выбрать, какой из них вызывать, поэтому вызов неоднозначен.Вы можете using родительские функции в Derived1, если вы не хотите их повторно использовать, или дать компилятору подсказку о том, какую базу использовать.

Если вы только закомментировать одну из функций в Derived1, тот, который вы вы оставите скрывает оба родителя версии, предотвращая либо один из них от выбран. На этом этапе вы можете вызвать тот, который вы определили, и не можете вызвать другой, если вы еще не сообщите компилятору, к какому конкретному базовому классу вы хотите его вызвать.

+0

С поддержкой перегрузки метода, я думаю, при проверке Base1 компилятор должен увидеть что-то вроде f_int; при проверке Base2 компилятор должен увидеть что-то вроде f_str. Таким образом, эти две функции f представляют собой две различные функции, а затем почему они будут скрывать другую? – user3511089