Могут ли функции принимать абстрактные базовые классы в качестве аргументов?

Почувствовав идею базовых классов и инкапсуляции, я начал понимать полиморфизм, но я не могу понять, как заставить его работать. Многие из примеров, которые я искал, встречаются как действительно, действительно принудительные (классы Foo и Bar просто слишком абстрактны для меня, чтобы увидеть эту утилиту), но вот как я понимаю основную концепцию: вы пишете базовый класс, получаете целая куча других вещей, которые изменяют то, что делают базовые методы (но не то, что они "есть" ), тогда вы можете писать общие функции, чтобы принимать и обрабатывать любые производные классы, потому что вы несколько стандартизировали их внешний вид. С этой предпосылкой я попытался реализовать базовую иерархию Animal- > cat/dog следующим образом:

class Animal {
  public:
    virtual void speak() = 0;
};

class Dog : public Animal {
  public:
    void speak() {cout << "Bark bark!" << endl;}
};

class Cat : public Animal {
  public:
    void speak() {cout << "Meow!" << endl;}
};

void speakTo(Animal animal) {
    animal.speak();
}

где говорить, что может взять, может взять общий вид животного и сделать это, ну, говорить. Но, как я понимаю, это не работает, потому что я не могу создать экземпляр Animal (в частности, в аргументе функции). Я спрашиваю, тогда я понимаю основную полезность полиморфизма, и как я могу действительно сделать то, что я пытался сделать?

Ответы

Ответ 1

Вы не можете передать объект Animal функции производного класса, потому что вы не можете создать объект Animal class et all, это Абстрактный класс.
Если класс содержит по крайней мере одну чистую виртуальную функцию (speak()), тогда класс становится абстрактным классом, и вы не можете создавать какие-либо его объекты. Однако вы можете создавать указатели или ссылки и передавать их им. Вы можете передать указатель Animal или ссылку на метод.

void speakTo(Animal* animal) 
{
    animal->speak();
}

int main()
{
    Animal *ptr = new Dog();
    speakTo(ptr);

    delete ptr;   //Don't Forget to do this whenever you use new()
    return 0;
}

Ответ 2

Вам нужно будет передать ссылку вместо копии:

void speakTo(Animal& animal) {
    animal.speak();
}