Как переопределить эту унаследованную функцию-член C ++ без использования виртуального ключевого слова? - PullRequest
1 голос
/ 08 июня 2010

У меня есть небольшая программа для демонстрации простого наследования. Я определяю класс Dog, который получен из Mammal. Оба класса совместно используют простую функцию-член с именем ToString (). Как Dog переопределяет реализацию в классе Mammal, когда я не использую ключевое слово virtual? (Мне даже нужно использовать виртуальное ключевое слово для переопределения функций-членов?)

mammal.h

#ifndef MAMMAL_H_INCLUDED
#define MAMMAL_H_INCLUDED

#include <string>

class Mammal
{
    public:
        std::string ToString();
};

#endif // MAMMAL_H_INCLUDED

mammal.cpp

#include <string>
#include "mammal.h"

std::string Mammal::ToString()
{
    return "I am a Mammal!";
}

dog.h

#ifndef DOG_H_INCLUDED
#define DOG_H_INCLUDED

#include <string>
#include "mammal.h"

class Dog : public Mammal
{
    public:
        std::string ToString();
};

#endif // DOG_H_INCLUDED

dog.cpp

#include <string>
#include "dog.h"

std::string Dog::ToString()
{
    return "I am a Dog!";
}

main.cpp

#include <iostream>
#include "dog.h"

using namespace std;

int main()
{
    Dog d;
    std::cout << d.ToString() << std::endl;
    return 0;
}

выход

I am a Dog!

Я использую MingW в Windows через Code :: Blocks.

Ответы [ 3 ]

8 голосов
/ 08 июня 2010

Ваш код напрямую использует объект Dog, поэтому, когда вы вызываете ToString(), он статически привязывается к Dog::ToString() и выдает «Я собака!».

Чтобы продемонстрировать полиморфизм, вы можете начать с указателя (или ссылки) на базовый класс, но установить его для ссылки на объект производного класса:

Dog d;
Mammal &m = d;

std::cout << m.ToString(); // will produce "I am a Mammal!".
std::cout << d.ToString(); // will produce "I am a Dog!"

Вызванный таким образом, если вы сделаете ToString виртуальным, вывод будет зависеть от типа объекта, на который указывает указатель, а не от типа самого указателя / ссылки (поэтому оба вызова выше приведут к «Я - собака ! ").

8 голосов
/ 08 июня 2010

Это не переопределение метода ToString в базовом классе, так как метод базового класса не virtual. Она просто скрывает эту функцию с помощью функции с идентичной сигнатурой.

Когда вы вызываете ToString() для объекта Dog, вызывается метод Dog::ToString. Зачем вызывать любой другой метод ToString(); объявление Dog:: найдено первым? virtual диспетчеризация происходит (и требуется только) при вызове через указатель или ссылку на объект базового класса.

Если вам нужно вызвать метод базового класса для объекта Dog, вам придется явно его квалифицировать.

d.Mammal::ToString()
1 голос
/ 22 ноября 2011

Попробуйте добавить виртуальный метод ToString() в классе Mammal. Я думаю, это то, что вы хотите.

class Mammal
{
    public:
        virtual std::string ToString();
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...