2016-02-21 3 views
0

Так что я смотрю на некоторые странные случаи Полиморпизма и неоднозначность. И есть один случай, который я не могу понять. Я не понимаю, почему последняя строка кода ниже действует таким образом.Виртуальное наследство/Полиморфизм

#include <stdio.h> 
#include <iostream> 

class Article 
{ 
public : 
    virtual bool compare(Article *a) { std::cout << "ACA" << std::endl;}; // ACA 
}; 

class Clothe : public Article 
{ 
    public : 
     bool compare (Clothe *c) { std::cout << "CCC" << std::endl;}; // CCC 
     bool compare (Article *a) { std::cout << "CCA" << std::endl;}; // CCA 
}; 



int main() 
{ 
Article *pta1 = new Article; 
Article *pta2 = new Clothe; 
Clothe *ptv1 = new Clothe; 

pta1->compare(pta2); // print ACA 
pta2->compare(pta1); // print CCA 
pta2->compare(pta2); // print CCA because compiler needs to explore pta2 to determine which compare to use. 
        // pta2 is instanced as a Clothe, so one of Clothe's compare will be called. 
        // And judging by its declaration pta2 is an Article (even thought it's instanced as a Clothe), 
        // so it will Call Clothe::Compare(Article*). I'm OK with this 

pta2->compare(ptv1); // print CCA ??? WHY , pta2 is explored, thus it's type is determined to be of type Clothe. 
        // And ptv1 is declared as a Clothe, so it should call Clothe::compare(Clothe* c) 
        // should print CCC, shouldn't it ? 
} 

Я потерян. Я не понимаю, как g ++ разрешает эту двусмысленность. Любая помощь/объяснение будет приятным. Спасибо за чтение и еще больше спасибо тем, кто отвечает.

PS: Я знаю, что сравнение должно возвращать bool, но здесь это не очень важно.

EDIT: опечатка надвигается во время моего переворота имен переменных на лету, имена изначально были на французском языке, извините за это. Теперь

+0

Проверьте свой код.Похоже, вы ошиблись в определении 'Clothe :: compare' – Lol4t0

+0

Да, действительно, он переводил имена переменных на лету на satckoverflow. Исправлено теперь спасибо, что заметили это. – aramir

+0

мой вопрос: почему нет bool Clothe :: compare (Clothe * c), вызываемый для pta2-> compare (ptv1); – aramir

ответ

2

Это фиксируется эта линия

pta2->compare(ptv1); 

отпечатки CCA, потому что есть только виртуальная функция bool compare(Article *a) в базовом классе.

Ваше предположение о pta2 неверно.

pta2 исследуется, поэтому его тип определяется как тип Clothe.

Это не тот случай. Тип pta2 - Article * и ничего больше. Он указывает только на объект Clothe, и поэтому можно вызвать через него функции Clothe, если (и только если) они присутствуют и виртуальны, а базовый класс и переопределены (с той же подписью!) В производном классе.

Проще говоря:

Компилятор только может «найти» перегрузкам в производном классе, которые присутствуют и виртуальной в базовом классе, если вызов выполняется с помощью указателя базового класса.

Что происходит здесь:

  1. pta2 является указателем на Article. Таким образом, при вызове compare рассматриваются различные возможности функций compare в Article.

  2. Единственный матч - bool Article::compare (Article *a).

  3. Теперь компилятор находит compare в Article виртуальным и использует некоторый внутренний механизм для совершения виртуального вызова через «vtable» объекта.

  4. Как Clothe переопределяет bool compare (Article *a), вызывается функция переопределения.

Базовый класс ничего не знает о bool compare (Clothe *c), так как он ничего не знает о Clothe и поэтому выход не CCV.

+0

Хорошо спасибо, я все понял неправильно. Спасибо, что разъяснил мне это. Я думал назад, дети-> мать, когда на самом деле она больше похожа на мать-> детей. – aramir

+0

Перечитав это, но почему g ++ разрешает использование статьи :: Clothe :: compare (статья * a), когда параметр ptv1/Clothe? – aramir

+1

@aramir: поскольку неявное преобразование указателя позволяет преобразовать указатель производного класса в указатель базового класса (недвусмысленный). – Pixelchemist

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