Base class pointer vs inherited class pointer? - c++

Suppose I have a class Dog that inherits from a class Animal. What is the difference between these two lines of code?
Animal *a = new Dog();
Dog *d = new Dog();
In one, the pointer is for the base class, and in the other, the pointer is for the derived class. But when would this distinction become important? For polymorphism, either one would work exactly the same, right?

For all purposes of type-checking, the compiler treats a as if it could point to any Animal, even though you know it points to a Dog:
You can't pass a to a function expecting a Dog*.
You can't do a->fetchStick(), where fetchStick is a member function of Dog but not Animal.
Dog *d2 = dynamic_cast<Dog*>(d) is probably just a pointer copy on your compiler. Dog *d3 = dynamic_cast<Dog*>(a) probably isn't (I'm speculating here, I'm not going to bother checking on any compiler. The point is: the compiler likely makes different assumptions about a and d when transforming code).
etc.
You can call virtual functions (that is, the defined polymorphic interface) of Animal equally through either of them, with the same effect. Assuming Dog hasn't hidden them, anyway (good point, JaredPar).
For non-virtual functions which are defined in Animal, and also defined (overloaded) in Dog, calling that function via a is different from calling it via d.

The answer to this question is a giant: It depends
There are numerous ways in which the type of the pointer could become important. C++ is a very complex language and one of the ways it shows up is with inheritance.
Lets take a short example to demonstrate one of the many ways in which this could matter.
class Animal {
public:
virtual void MakeSound(const char* pNoise) { ... }
virtual void MakeSound() { ... }
};
class Dog : public Animal {
public:
virtual void MakeSound() {... }
};
int main() {
Animal* a = new Dog();
Dog* d = new Dog();
a->MakeSound("bark");
d->MakeSound("bark"); // Does not compile
return 0;
}
The reason why is a quirk of the way C++ does name lookup. In Short: When looking for a method to call C++ will walk the type hierarchy looking for the first type which has a method of the matching name. It will then look for a correct overload from the methods with that name declared on that type. Since Dog only declares a MakeSound method with no parameters, no overload matches and it fails to compile.

The first line allow you to call only members of the Animal class on a :
Animal *a = new Dog();
a->eat(); // assuming all Animal can eat(), here we will call Dog::eat() implementation.
a->bark(); // COMPILATION ERROR : bark() is not a member of Animal! Even if it's available in Dog, here we manipulate an Animal.
Although (as pointed by others), in this cas as a is still an Animal, you can't provide a as a parameter of a function asking for a more specific child class that is Dog :
void toy( Dog* dog );
toy( a ); // COMPILATION ERROR : we want a Dog!
The second line allow you to use specific functions of the child class :
Dog *a = new Dog();
a->bark(); // works, but only because we're manipulating a Dog
So use the base class as the "generic" interface of your class hierarchy (allowing you to make all your Animals to eat() whithout bothering about how).

The distinction is important when you call a virtual function using the pointer. Let's say Animal and Dog both have functions called do_stuff().
If Animal::do_stuff() is declared virtual, calling do_stuff() on an Animal pointer will call Dog::do_stuff().
If Animal::do_stuff() is not declared virtual, calling do_stuff() on an Animal pointer will call Animal::do_stuff().
Here's a full working program to demonstrate:
#include <iostream>
class Animal {
public:
void do_stuff() { std::cout << "Animal::do_stuff\n"; }
virtual void virt_stuff() { std::cout << "Animal::virt_stuff\n"; }
};
class Dog : public Animal {
public:
void do_stuff() { std::cout << "Dog::do_stuff\n"; }
void virt_stuff() { std::cout << "Dog::virt_stuff\n"; }
};
int main(int argc, char *argv[])
{
Animal *a = new Dog();
Dog *b = new Dog();
a->do_stuff();
b->do_stuff();
a->virt_stuff();
b->virt_stuff();
}
Output:
Animal::do_stuff
Dog::do_stuff
Dog::virt_stuff
Dog::virt_stuff
This is just one example. The other answers list other important differences.

No, they aren't the same.
The Dog pointer is not as polymorphic as Animal. All it can point to at runtime is a Dog or a subclass of Dog. If there are no subclasses of Dog, then the Dog runtime type and compile time types are the same.
The Animal pointer can refer to any subclass of Animal: Dog, Cat, Wildebeast, etc.

The difference is important when you try to call Dog's methods that are not Animal's method. In the first case (pointer to Animal) you have to cast the pointer to Dog first. Another difference is if you happen to overload non-virtual method. Then either Animal::non_virtual_method() (pointer to Animal) or Dog::non_virtual_method(pointer to Dog) will be called.

You must always remember there are 2 parts in every class, the data and the interface.
Your code truly created 2 Dog objects on the heap. Which means the data is of Dog.
This object is of size the sum of all data members Dog + Animal + the vtable pointer.
The ponters a and d (lvalues) differ as from a interface point of view. Which determines how you can treat them code wise. So even though Animal* a is really a Dog, you could not access a->Bark() even if Dog::Bark() existed. d->Bark() would have worked fine.
Adding the vtable back into the picture, assuming the interface of Animal had Animal::Move a generic Move() and that Dog really overwriten with a Dog::Move() { like a dog }.
Even if you had Animal a* and performed a->Move() thanks to the vtable you would actually Move() { like a dog }. This happens because Animal::Move() was a (virtual) function pointer re-pointed to Dog's::Move() while constructing Dog().

It makes no real difference at run time, as the two instances are the same. The only difference is at compile time, where you could call for example d->bark() but not a->bark(), even if a actually contains a dog. The compiler considers the variable to be an animal and only that.

Related

Virtual Print function not working properly for the derived class [duplicate]

Consider the following example:
#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();
}
The output is:
rawr
bark
rawr
bark
But I thought that surely the output should be "rawr bark bark bark". What's with the badDog?
Update: You may be interested in another question of mine.
This is a problem called "slicing."
Dog() creates a Dog object. If you were to call Dog().makeSound(), it would print "bark" as you expect it to.
The problem is that you are initializing the badDog, which is an object of type Animal, with this Dog. Since the Animal can only contain an Animal and not anything derived from Animal, it takes the Animal part of the Dog and initializes itself with that.
The type of badDog is always Animal; it can never be anything else.
The only way you can get polymorphic behavior in C++ is using pointers (as you have demonstrated with your goodDog example) or using references.
A reference (e.g., Animal&) can refer to an object of any type derived from Animal and a pointer (e.g., Animal*) can point to an object of any type derived from Animal. A plain Animal, however, is always an Animal, nothing else.
Some languages like Java and C# have reference semantics, where variables are (in most cases) just references to objects, so given an Animal rex;, rex is really just a reference to some Animal, and rex = new Dog() makes rex refer to a new Dog object.
C++ doesn't work that way: variables don't refer to objects in C++, variables are objects. If you say rex = Dog() in C++, it copies a new Dog object into rex, and since rex is actually of type Animal, it gets sliced and just the Animal parts get copied. These are called value semantics, which are the default in C++. If you want reference semantics in C++, you need to explicitly use references or pointers (neither of these are the same as references in C# or Java, but they are more similar).
Animal badDog = Dog();
ad.makeSound();
When you instantiate a Dog and assign it by-value to an Animal variable, you slice the object. Which basically means you strip off all the Dog-ness from badDog and make it in to the base class.
In order to use polymorphism with base classes, you must use either pointers or references.
You initialized badDog using the assignment operator. Thus Dog() was copied as Animal. The output of your program is correct. :)

dynamic cast with inheritance hierarchies

so I have this code:
Base* objbase = new Derived();
//perform a downcast at runtime with dynamic_cast
Derived* objDer = dynamic_cast<Derived*>(objBase);
if(objDer)//check for success of the cast
objDer->CallDerivedFunction();
This is a snippet of code for a cast operators section in my book.
Now why do I have this, I don't understand what's the point of having to dynamically cast a pointer to a base object pointing to a Derived object; For me, that's something to do with polymorphism giving us the ability to do objBase->DeriveClassFunction(), but I don't really know.
In the first place why does it do this: Base* objbase = new Derived();, and then why does it cast a base object pointer to a Derived again, I can't quite figure out why.
Thanks in advance.
That code snippet is just a demonstration of what's possible. It describes a tool, what you do with this tool is up to you. A slightly bigger example might be:
class Animal {
void Feed();
};
class Cat : public Animal { /*...*/ };
class Dog : public Animal {
// Only dogs need to go out for a walk
void WalkTheDog();
};
void Noon(Animal* pet)
{
// No matter what our pet is, we should feed it
pet->Feed();
// If our pet is a dog, we should also take it out at noon
Dog* dog = dynamic_cast<Dog*>(pet);
if(dog) // Check if the cast succeeded
dog->WalkTheDog();
}
Noon(new Cat()); // Feed the cat
Noon(new Dog()); // Feed the dog and take him out
Notice that every animal has the Feed() function, but only dogs have the WalkTheDog() function, so in order to call that function, we need to have a pointer to a dog. But it would also be quite a waste to copy the Noon() function for both types, especially if we might later add even more animals. So instead, the Noon() function works for any kind of animal, and does only the dog-specific things only if the animal is actually a dog.

C++ Casting From Parent to Child After Passing as a Function?

I was wondering if this (above title) is exactly possible when it comes to inheriting from an interface within C++.
class Animal
{
public:
virtual void Eat(Animal& a) = 0; //Function that attempts to eat an animal.
}
class Dog : Animal
{
public:
void Eat(Animal& a);
}
void Dog::Eat(Animal& a)
{
Dog d = (Dog) a;
// Do something.
}
int main()
{
Dog dog1 = Dog();
Dog dog2 = Dog();
dog1.Eat(dog2);
return;
}
So basically, I know that the animal that my dog is going to be eating is only other dogs (in all cases ever, not just in this specific example). However, I am inheriting from a purely virtual class Animal which requires me to define the function with the Animal parameter.
I know that having a parameter as Animal causes the function Dog::Eat to think that the parameter is an Animal and not a Dog. However, considering that the data for the object to be represented as a Dog is still there I am pretty sure that there is a way to establish (cast, etc) the Animal as a Dog, I just don't know how and I am not quite sure how to search.
So I am wondering how I would do this. I am pretty sure that you can use a dynamic cast or a reinterpret cast, but I am under the impression that you typically want to minimize the use of these casts if you can. I am pretty new to Object Oriented within C++ since I used to mainly use only C.
You can indeed cast it (assuming you intended Dog to be derived publicly from Animal); but you would have to cast a reference or pointer. Your cast to a value would try to create a new Dog from the Animal that was passed in; and there is no suitable conversion for that.
// safest, if you can't guarantee the type
Dog & d = dynamic_cast<Dog&>(a); // throws if wrong type
Dog * d = dynamic_cast<Dog*>(&a); // gives null if wrong type
// fastest, if you can guarantee the type
Dog & d = static_cast<Dog&>(a); // goes horribly wrong if wrong type
Don't use reinterpret_cast; that allows all sorts of crazy conversions, so it's easy to do something wrong. Don't use the C-style cast (Dog&)a either - that allows even more conversions than reinterpret_cast, and has a syntax that's subtle and difficult to search for.
In general, you shouldn't need a cast at all - try to design the base class so that it exposes everything you want to do with it, with no need to know the actual object type.

Instantiating c++ interface as a child class

I have an interface, let's call it Creature, who has virtual functions that cause it to be abstract.
I have child classes of this interface such as Dog, Cat, and Pig.
The compiler doesn't seem to like the following line due to not being able to declare variable thing to be of abstract type Creature.
Creature thing = Dog();
I know I can't instantiate interfaces and the like, but this is just a Dog being declared as a Creature.
I need some way of having one declaration work for all the children (i.e., being able to put Dog(), Cat(), or Pig() where Dog() is in the line above).
Can this be done in c++ or am I misusing inheritance and interfaces completely?
Object types themselves are not polymorphic in C++. The line you've given declares a Creature object and then attempts to initialise it with a Dog object. If Creature weren't abstract, this would result in slicing - thing wouldn't be a Dog any more, it would just be a Creature. Since it is abstract, you simply can't have a Creature object anyway.
You need to use pointers or references for polymorphic behaviour. Consider for example:
Creature* thing = new Dog();
You can now dereference thing and use it as a Creature, even though it's dynamic type is Dog. However, using raw pointers like this is usually not recommended, as you have to manually ensure that the object is deleted at some point. The ownership can become confusing. Your best bet is to put it in a smart pointer, such as:
std::unique_ptr<Creature> thing(new Dog()); // or std::make_unique when we have it
Here, I've demonstrated std::unique_ptr, but the choice of smart pointer will depend on the ownership semantics for that object. A common alternative is std::shared_ptr.
To demonstrate polymorphism with references:
Dog dog;
Creature& thing = dog;
// Can now use dog as a Creature
In C++ you have to realize the different between value and reference semantics, where-as in interpretet languages you tend to just deal with reference semantics (except for some odd cases with plain old data objects which have value semantics but besides the point).
In C++ all objects are values, e.g an object can never be null, this has the implication that declaration specifies the storage requirement.
Consider the following
struct creature {
};
struct dog : public creature {
float cuteness;
};
The storage requirement for a dog is different than that of a creature, even if you allow the conversion this would result in slicing.
For example, will fido bark or be silent?
#include
class creature {
public:
virtual void speak() {
std::cout << "..." << std::endl;
}
};
class dog : public creature {
public:
virtual void speak() {
std::cout << "woof!" << std::endl;
}
};
int main(int argc, const char *argv[]) {
creature fido;
fido = dog();
fido.speak();
return 0;
}
However if you were to simply have a pointer or reference to the object it is a different matter.
By pointer.
creature* fido = new dog();
fido->speak();
delete fido;
By reference.
dog fido;
creature& c = fido;
c.speak();
Beyond the scope of this question, but optionally a smart pointer.
std::unique_ptr<creature> fido(new dog);

Learning C++: polymorphism and slicing

Consider the following example:
#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();
}
The output is:
rawr
bark
rawr
bark
But I thought that surely the output should be "rawr bark bark bark". What's with the badDog?
Update: You may be interested in another question of mine.
This is a problem called "slicing."
Dog() creates a Dog object. If you were to call Dog().makeSound(), it would print "bark" as you expect it to.
The problem is that you are initializing the badDog, which is an object of type Animal, with this Dog. Since the Animal can only contain an Animal and not anything derived from Animal, it takes the Animal part of the Dog and initializes itself with that.
The type of badDog is always Animal; it can never be anything else.
The only way you can get polymorphic behavior in C++ is using pointers (as you have demonstrated with your goodDog example) or using references.
A reference (e.g., Animal&) can refer to an object of any type derived from Animal and a pointer (e.g., Animal*) can point to an object of any type derived from Animal. A plain Animal, however, is always an Animal, nothing else.
Some languages like Java and C# have reference semantics, where variables are (in most cases) just references to objects, so given an Animal rex;, rex is really just a reference to some Animal, and rex = new Dog() makes rex refer to a new Dog object.
C++ doesn't work that way: variables don't refer to objects in C++, variables are objects. If you say rex = Dog() in C++, it copies a new Dog object into rex, and since rex is actually of type Animal, it gets sliced and just the Animal parts get copied. These are called value semantics, which are the default in C++. If you want reference semantics in C++, you need to explicitly use references or pointers (neither of these are the same as references in C# or Java, but they are more similar).
Animal badDog = Dog();
ad.makeSound();
When you instantiate a Dog and assign it by-value to an Animal variable, you slice the object. Which basically means you strip off all the Dog-ness from badDog and make it in to the base class.
In order to use polymorphism with base classes, you must use either pointers or references.
You initialized badDog using the assignment operator. Thus Dog() was copied as Animal. The output of your program is correct. :)