Beschouw het volgende voorbeeld:
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void makeSound() {cout << "rawr" << endl;}
};
class Dog : public Animal
{
public:
virtual void makeSound() {cout << "bark" << endl;}
};
int main()
{
Animal animal;
animal.makeSound();
Dog dog;
dog.makeSound();
Animal badDog = Dog();
badDog.makeSound();
Animal* goodDog = new Dog();
goodDog->makeSound();
}
De uitvoer is:
rawr
bark
rawr
bark
Maar ik dacht dat de output zeker “rawr bark barkbark” zou moeten zijn. Wat is er met de badDog?
Update: misschien ben je geïnteresseerd in een andere vraag van mij.
Antwoord 1, autoriteit 100%
Dit is een probleem dat ‘slicing’ wordt genoemd.
Dog()
maakt een Dog
-object aan. Als je Dog().makeSound()
zou aanroepen, zou het “blaffen” afdrukken zoals je zou verwachten.
Het probleem is dat je de badDog
, een object van het type Animal
, initialiseert met deze Dog
. Aangezien het Animal
alleen een Animal
kan bevatten en niet iets dat is afgeleid van Animal
, neemt het het Animal
-gedeelte van de Dog
en initialiseert zichzelf daarmee.
Het type badDog
is altijd Animal
; het kan nooit iets anders zijn.
De enige manier waarop u polymorf gedrag in C++ kunt krijgen, is door gebruik te maken van aanwijzers (zoals u heeft aangetoond met uw voorbeeld van goodDog
) of door verwijzingen te gebruiken.
Een verwijzing (bijv. Animal&
) kan verwijzen naar een object van elk type afgeleid van Animal
en een pointer (bijv. Animal*
) kan verwijzen naar een object van elk type afgeleid van Animal
. Een gewoon Animal
is echter altijd een Animal
, niets anders.
Sommige talen zoals Java en C# hebben referentiesemantiek, waarbij variabelen (in de meeste gevallen) slechts verwijzingen naar objecten zijn, dus gegeven een Animal rex;
, is rex
echt alleen een verwijzing naar een Animal
, en rex = new Dog()
zorgt ervoor dat rex
verwijst naar een nieuw Dog
-object .
C++ werkt niet op die manier: variabelen verwijzen niet naar objecten in C++, variabelen zijn objecten. Als je rex = Dog()
in C++ zegt, kopieert het een nieuw Dog
-object naar rex
, en sinds rex
is eigenlijk van het type Animal
, het wordt in plakjes gesneden en alleen de Animal
delen worden gekopieerd. Dit worden waardesemantiek genoemd, wat de standaard is in C++. Als je referentiesemantiek in C++ wilt, moet je expliciet referenties of pointers gebruiken (geen van beide is hetzelfde als referenties in C# of Java, maar ze lijken meer op elkaar).
Antwoord 2, autoriteit 13%
Animal badDog = Dog();
ad.makeSound();
Als je een Dog
instantieert en deze een waarde toewijst aan een Animal
variabele, dan snijdhet object. Wat in feite betekent dat je alle Dog
-ness van badDog
verwijdert en in de basisklasse komt.
Om polymorfisme met basisklassen te gebruiken, moetofwel pointers ofwel verwijzingen worden gebruikt.
Antwoord 3
Je hebt badDog geïnitialiseerd met de toewijzingsoperator. Dus Dog() werd gekopieerd als Animal. De uitvoer van uw programma is correct. 🙂