I have a question about creating classes from an abstract class and how data gets cut.
Let's say we have an abstract class called Animal, and classes called Cat and Dog that implement said class. Both these classes implement a method from Animal called update(); however, in their update methods they access private methods and/or variables that are exclusive to themselves and not the Animal class. I understand that if we declare the classes in this manner...
Animal* dog = new Dog();
Animal* cat = new Cat();
We're only able to access methods or variables that only the Animal class specifically has; however, what if I called the update() method on each class instead, and this update method calls on the exclusive members in Cat and Dog. Would that be legal, or would this data be truncated because I created them as Animal?
The language does not force you to use only the polymorphic access to method 'update()'.
Example:
class Animal {
public:
virtual void update() { std::cout << "Animal::update() " << std::endl; }
virtual ~Animal(){}
};
class Cat : public Animal {
public:
virtual ~Cat(){}
virtual void update() { std::cout << "Cat::update() " << std::endl; }
};
class Dog : public Animal {
public:
virtual ~Dog(){}
virtual void update() { std::cout << "Dog::update() " << std::endl; }
};
int t395(void)
{
Animal* dog = new Dog();
Animal* cat = new Cat();
dog->update();
cat->update();
dog->Animal::update();
return (0);
}
// OUTPUT:
// Dog::update()
// Cat::update()
// Animal::update()
...We're only able to access methods or variables that only the Animal
class specifically has;
I agree ... dog is an Animal, and does not have a method Bark, and thus would not be able to invoke dog->bark(). But, you could add a method "virtual void talk()" to all three, and perhaps a virtual void Dog::talk() would simply invoke its local Dog::bark() method, and Cat::talk() would simply invoke it's local Cat::meow() method.
however, what if I called the update() method on each class instead,
and this update method calls on the exclusive
members in Cat and Dog. Would that be legal, or would this data be
truncated because I created them as Animal?
Legal - yes. Data is NOT truncated (in either Animal or Dog or Cat)
a) The polymorphic dog is-a Animal, and has all methods and data attributes of Animal.
b) It also has all the methods and attributes of Dog.
Implementation is compiler specific, but one typical impl. is that the two structures (there are some complication needing compiler attention) are simply concatenated in memory. Which is first doesn't matter - its an implementation issue.
Both cat and dog instances have access to their own data and method attributes, regardless of if these method are not mapped into the polymorphic table.
Also, both cat and dog instances have access to those parts of the parent Animal instance that are public or protected (but not private).
Not sure I fully understand your question, but your update() describes a virtual function call.
I suspect you are having problems understanding how inheritance and polymorphism is implemented, I know I did. Consider the following:
class base
{
private:
int mylocalInt; //inaccessible to anyone but the base.
protected:
int sharedInt = 5;//accessible by base, and any subtype.
public:
base()
{
cout<<"creating base object"<<endl;
}
virtual ~base()
{
cout<<"Now destroying base object"<<endl;
}
void virtual callMe()//will be overridden, only called if you directly instantiate a base object.
{
cout<<"I am a base"<<endl;
}
};
class subtypeA : public base
{
private:
int Aint;
public:
subtypeA()
{
cout<<"creating subtype"<<endl;
}
~subtypeA()
{
cout<<"destroying subtype"<<endl;
}
void callMe()
{
cout<<"I am a subtypeA"<<endl;
}
int getAint()//this is a local, IE static function, a base ptr cannot access it.
{
return Aint;
}
int getSharedInt()//notice how sharedInt, located in the base object, is still accessible from within the subtype.
{
return sharedInt;
}
};
int main(int argc, char* argv[] )
{
base* ptr = new subtypeA;
ptr->callMe();//works fine, will check which subtype, if any, ptr points to, and call the appropriate callMe(). This is because
//callMe() is virtual in base.
//ptr->sharedInt//illegal, main is not part of base or a subtype of base.
subtypeA* Aptr = (subtypeA*)ptr;//since all pointers are the same size, they can be cast to one another, is dangerous however
cout<<Aptr->getSharedInt()<<endl;//works, getSharedInt is NOT virtual, but a normal static member of subtypeA, so in order to use it, the pointer
//needs to be of type subtypeA. the sharedInt however is protected, so subtypeA can access it due to the fact that it is related to it's owner, base.
}
Now take that, and play around with it, add a subtypeB, then add subtype to that subtype, IE subtypeAA and BB for instance.
Notice that each individual class is still it's own object, distinct from any of the objects it is related to. So if a variable is private, it can't be directly accessed from the outside, just as with normal objects.
Again: There is nothing truly special about polymorphism, all it is is a nice abstraction hiding the "ugly" type-checking and so forth going on to facilitate virtual calls.
I completely forgot about your other question. No, you never have to worry about truncation in this case. In fact I asked more or less the same question some time ago, take a look: C++ subtype degeneration when placed in a container
dasblinkenlight explains it brilliantly.
Related
I'm having a rough time with a particular C++ inheritance problem. Say we have two abstract classes, one using the other as argument type for one of the pure virtual functions:
class Food {
public:
int calories=0;
virtual void set_calories(int cal)=0;
}
class Animal {
public:
int eaten_calories=0;
virtual void eat_food(Food &f)=0;
}
Now, we create a derived class for each, and we instantiate a virtual function with arguments of type the derived class:
class Vegetables: public Food{
public:
void set_calories(int cal){calories=cal;}
}
class Cow: public Animal{
public:
void eat_food(Vegetables &v){this->eaten_calories += v.calories;}
}
The problem with this is that the function eat_food requires a signature with the abstract class Food, or else a Cow() object creation won't compile, complaining that Cow is an abstract class because no suitable implementation of eat_food(Food f) was found.
Update: An additional constraint I seek for the implementation is that a second class Meat: public Food should not be usable with Cow::eat_food(f). In short, just setting Cow::eat_food(Food f) and casting to Vegetables wouldn't cut it.
What is the best way to overcome this error?
So far I have found two options:
Creating an eat_food(Food f) implementation in Cow with a try/catch to check if f can be safely casted to Vegetables, and then calling eat_food(Vegetables v). PROBLEM: if you have 50 virtual functions, this forces you to write 50 additional function implementations in Cow.
Turn the Animal into a Template class Animal<T>, and instantiate it with each of the derived classes of Food to define the animals (e.g., class Cow: public Animal<Vegetables>). PROBLEM: you can no longer define an Animal* pointer to hold an undefined animal with not known type.
Is there any viable/stylish alternative to these two? Maybe a software pattern of some kind?
When you defined the virtual function Animal::eat_food() accepting a Food& parameter, you declared that for any Animal, you can provide any Food to eat_food(). Now you want to break that promise. This brings into question your design. Either it is legitimate to call ptr->eat_food(food) where ptr is an Animal* and food is a Meat, or eat_food() should (probably) not be defined in the Animal class. If you cannot substitute one Food for another, use of Food& is likely a mistake. If you cannot substitute one Animal for another, defining at the Animal level is likely a mistake.
Perhaps a small change in nomenclature would help this make more sense. Consider renaming eat_food to give_food, or perhaps feed. Now you have a concept that is applicable to all animals. You can feed any food to any animal, but whether or not the animal eats it is a different story. Maybe you should make your virtual function feed() so that it applies equally well to all animals. If you have an Animal* and a Food&, you can feed the animal, but it's the animal that decides if it eats. If you were to instead insist that you must know the correct type of Food before feeding the Animal, then you should have a Cow* instead of an Animal*.
Note: If you happen to be in a case where you never try to feed an Animal*, then you could remove the virtual function from Animal, in which case your question becomes moot.
This might look something like the following.
class Animal {
int eaten_calories=0;
protected:
void eat_food(Food &f) { eaten_calories += f.calories; } // Not virtual
public:
virtual void feed(Food &f)=0;
};
class Cow: public Animal{
public:
void feed(Food &f) override {
// Cows only eat Vegetables.
if ( dynamic_cast<Vegetables*>(&f) ) // if `f` is a Vegetables
eat_food(f);
else
stampede(); // Or whatever you think is amusing (or appropriate).
}
};
Note that I have kept your eat_food() implementation, but moved it to a non-virtual function in Animal. This is based on an assumption, so it might be inappropriate. However, I am willing to assume that no matter what type of animal, and no matter what type of food, if the animal actually eats the food, then the eaten calories should increase by the food's calories.
In addition, a rule of thumb says that this might be the correct level of abstraction -- the two bits of data being used, calories and eaten_calories, belong directly to the two classes being used, Animal and Food. This suggests (just a rule of thumb) that your logic and data are at a consistent level of abstraction.
Oh, I also specified protected access for eat_food(). This way it is the object's decision whether or not to eat. No one will be able to force an animal to eat; they would only be able to offer it food. This demonstrates another principle of polymorphic design: when derived classes differ, only the objects of those classes should need to be aware of those differences. Code that sees only objects of a common base should not need to test for these differences in advance of using those objects.
If you pass around a polymorphic type (like Vegetables) as a base type by value (like Food f), you will slice the object, which prevents overriden methods from being called.
You need to pass such types by pointer or by reference instead, eg:
class Food {
public:
virtual int get_calories() const = 0;
};
class Animal {
public:
int eaten_calories = 0;
virtual void eat_food(Food& f) = 0;
};
class Vegetables: public Food {
public:
int get_calories() const { return ...; }
};
class Cow: public Animal{
public:
void eat_food(Food& f){ this->eaten_calories += f.get_calories(); }
};
Vegetables veggies;
Cow cow;
cow.eat_food(veggies);
UPDATE:
You can't change the signature of a virtual method in derived classes (except when using covariant return types). Since eat_food() is exposed in Animal and takes a Food&, if you want Cow::eat_food() to accept only a Vegetables object and not a Meat object, then it needs to check at runtime if the input Food& refers to a Vegetables object and if not then throw an exception. dynamic_cast does exactly that for you when casting a reference, eg:
class Cow: public Animal{
public:
void eat_food(Food& f){ this->eaten_calories += dynamic_cast<Vegetables&>(f).calories; }
};
Vegetables veggies;
Meat meat;
Cow cow;
cow.eat_food(veggies); // OK
cow.eat_food(meat); // throws std::bad_cast
I am confused about the concepts of inheritance and polymorphism. I mean, what is the difference between code re-usability and function overriding? Is it impossible to reuse parent class function using inheritance concept or else is it impossible to override parent class variables using Polymorphism. There seems little difference for me.
class A
{
public:
int a;
virtual void get()
{
cout<<"welcome";
}
};
class B:public A
{
a =a+1; //why it is called code reuse
void get() //why it is called overriding
{
cout<<"hi";
}
};
My doubt is about the difference between the code reuse and function overriding.
Lets start with your example.
class A
{
public:
int a;
virtual void get()
{
cout<<"welcome";
}
};
class B:public A
{
a =a+1; //why it is called code reuse
void get() //why it is called overriding
{
cout<<"hi";
}
};
Inheritance: Here you are deriving class B from class A, this means that you can access all of its public variables and method.
a = a + 1
Here you are using variable a of class A, you are reusing the variable a in class B thereby achieving code reusability.
Polymorphism deals with how a program invokes a method depending on the things it has to perform: in your example you are overriding the method get() of class A with method get() of class B. So when you create an instance of Class B and call method get you'll get 'hi' in the console not 'welcome'
Function inheritance allows for abstraction of behaviour from a "more concrete" derived class(es) to a "more abstract" base class. (This is analogous to factoring in basic math and algebra.) In this context, more abstract simply means that less details are specified. It is expected that derived classes will extend (or add to) what is specified in the base class. For example:
class CommonBase
{
public:
int getCommonProperty(void) const { return m_commonProperty; }
void setCommonProperty(int value) { m_commonProperty = value; }
private:
int m_commonProperty;
};
class Subtype1 : public CommonBase
{
// Add more specific stuff in addition to inherited stuff here...
public:
char getProperty(void) const { return m_specificProperty1; }
private:
char m_specificProperty1;
};
class Subtype2 : public CommonBase
{
// Add more specific stuff in addition to inherited stuff here...
public:
float getProperty(void) const { return m_specificProperty2; }
private:
float m_specificProperty2;
};
Note that in the above example, getCommonProperty() and setCommonProperty(int) are inherited from the CommonBase class, and can be used in instances of objects of type Subtype1 and Subtype2. So we have inheritance here, but we don't really have polymorphism yet (as will be explained below).
You may or may not want to instantiate objects of the base class, but you can still use it to collect/specify behaviour (methods) and properties (fields) that all derived classes will inherit. So with respect to code reuse, if you have more than one type of derived class that shares some common behaviour, you can specify that behaviour only once in the base class and then "reuse" that in all derived classes without having to copy it. For example, in the above code, the specifications of getCommmonProperty() and setCommonProperty(int) can be said to be reused by each Subtype# class because the methods do not need to be rewritten for each.
Polymorphism is related, but it implies more. It basically means that you can treat objects that happen to be from different classes the same way because they all happen to be derived from (extend) a common base class. For this to be really useful, the language should support virtual inheritance. That means that the function signatures can be the same across multiple derived classes (i.e., the signature is part of the common, abstract base class), but will do different things depending on specific type of object.
So modifying the above example to add to CommonBase (but keeping Subtype1 and Subtype2 the same as before):
class CommonBase
{
public:
int getCommonProperty(void) const { return m_commonProperty; }
void setCommonProperty(int value) { m_commonProperty = value; }
virtual void doSomething(void) = 0;
virtual ~CommonBase() { }
private:
int m_commonProperty;
};
Note that doSomething() is declared here as a pure virtual function in CommonBase (which means that you can never instantiate a CommonBase object directly -- it didn't have to be this way, I just did that to keep things simple). But now, if you have a pointer to a CommonBase object, which can be either a Subtype1 or a Subtype2, you can call doSomething() on it. This will do something different depending on the type of the object. This is polymorphism.
void foo(void)
{
CommonBase * pCB = new Subtype1;
pCB->doSomething();
pCB = new Subtype2;
pCB->doSomething(); // Does something different...
}
In terms of the code sample you provided in the question, the reason get() is called "overriding" is because the behaviour specified in the B::get() version of the method takes precedence over ("overrides") the behaviour specified in the A::get() version of the method if you call get() on an instance of a B object (even if you do it via an A*, because the method was declared virtual in class A).
Finally, your other comment/question about "code reuse" there doesn't quite work as you specified it (since it's not in a method), but I hope it will be clear if you refer to what I wrote above. When you are inheriting behaviour from a common base class and you only have to write the code for that behaviour once (in the base class) and then all derived classes can use it, then that can be considered a type of "code reuse".
You can have parametric polymorphism without inheritance. In C++, this is implemented using templates. Wiki article:
http://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29#Parametric_polymorphism
I have one class called Animal
class Animal
{
std::string name;
public:
Animal(string n)
{
name = n;
}
string getname()
{
return name;
}
};
and two inherited classes Cat and Dog
class Cat : public Animal
{
public:
Cat(string name):Animal(name)
{}
};
class Dog : public Animal
{
public:
Dog(string name):Animal(name){}
};
and i have a class called AnimalQueue which contains 2 lists, cat list and dog list
class AnimalQueue
{
std::list<Cat*> cats;
std::list<Dog*> dogs;
public:
void Enqueue(Animal a)
{
if(a.getname().compare("Cat") == 0)
{
// what should i do here
}
else
{
// what should i do here
}
}
};
what i want it, when i enter cat then it should go to the cat list and same with dog also in Enqueue function. I am not sure how it would work, how can i type cast from Animal to Cat or to Dog.
I tried
Cat *c = (Cat*) &a;
but it dows not work.
int main()
{
string name = "Cat";
Cat c(name);
name = "Dog";
Dog d(name);
AnimalQueue aq;
aq.Enqueue(c);
aq.Enqueue(d);
}
This is working code, you can copy paste in your editor. you can change the signature of Animal or whatever you want so it can help to make my concept clear about type casting in inheritance.
For reference, here's how this code might look in C++:
#include <string>
#include <utility>
#include <vector>
class Animal
{
std::string name_;
public:
explicit Animal(std::string name) : name_(std::move(name)) {}
virtual ~Animal() {}
};
class Cat : public Animal { using Animal::Animal; };
class Dog : public Animal { using Animal::Animal; };
class AnimalQueue
{
std::vector<Cat> cats_;
std::vector<Dog> dogs_;
public:
void Enqueue(Animal const & animal)
{
if (Cat const * p = dynamic_cast<Cat const *>(&animal))
{
cats_.push_back(*p);
}
else if (Dog const * p = dynamic_cast<Dog const *>(&animal))
{
dogs_.push_back(*p);
}
else
{
// discarding unrecognized animal
}
}
};
Usage:
AnimalQueue q;
q.Enqueue(Dog("dog"));
q.Enqueue(Cat("cat"));
Notes:
C++ basics:
Don't say using namespace std.
The container of choice is std::vector, not std::list.
Avoid implicit conversions. Everything is explicit unless required otherwise.
The string-sink constructor moves from its argument.
Adopt systematic naming conventions for class data members.
No need for loads of local variables; you can put arbitrary expressions into function calls.
My concrete classes inherit constructors for reasons of laziness. In a real setting, you may need to write your own constructors.
Polymorphism:
The polymorphic base has a virtual destructor.
Polymorphism can be used when arguments are passed as pointers or references to a base subobjects.
High-level design:
As written, there seems little reason to have a polymorphic base, since your entire code is static. Several distinct overloads (for Cat and Dog) would be more appropriate.
Polymorphic bases are needed when the concrete type cannot be known until runtime. In that case you won't have concrete-typed variables, and you will need to create objects dynamically. When that happens, you will want to pass around std::unique_ptr<Animal>, and the dynamic casts will have to be adjusted.
There are two problems that are fairly evident in your code:
You are not allowing dynamic binding
You have a slicing problem.
Dynamic binding
Dynamic binding is when a name is bound to a function at runtime rather than compile time. If you are dealing with runtime polymorphism, using dynamic binding allows you call functions using the dynamic type of the object (Dog) rather than its static type (Animal). This is useful because when derived classes override inherited base class functions, it is preferable to call the derived class function rather than the base class one.
To achieve dynamic binding in C++, you need to incorporate virtual functions. If you use virtual functions, the compiler will delay evaluating the name of the function until runtime where it can use the object's virtual table1 to bind the name to the address of the correct function.
To give getname() dynamic binding, declare it with the virtual specifier:
virtual string getname();
If a derived class overrides this function, that will be the one that is invoked, otherwise the base class's version will be called. This virtual function can be thought of as a default implementation.
The Slicing Problem
Slicing occurs when you copy the base part of a derived class instance. This can happen for instance when you take a base class argument by value and pass in a derived class - the derived part will be "sliced" off. When that happens you only have the static part of the object off of which to call functions and access data - hence why calling getname() in Enqueue() always calls Animal::getname().
To prevent this, you must use either a reference or pointer to a base class. This prevents slicing because no copying occurs when passing around references or pointers.
Make Enqueue take an lvalue-reference to an Animal instance:
void Enqueue(Animal const& a);
Important: If you are using base class pointer to a derived instance, in order to prevent Undefined Behavior, you must give the base class a virtual destructor. Doing so allows the derived class' destructor to be called along with the base class' destructor.
This is simply an explanation of your issues, you can refer to #Kerrek SB's answer for a good solution.
1 Virtual tables are a non-standard implementation, it really depends on your system how virtual function names are resolved.
What is the purpose of using the reserved word virtual in front of functions? If I want a child class to override a parent function, I just declare the same function such as void draw(){}.
class Parent {
public:
void say() {
std::cout << "1";
}
};
class Child : public Parent {
public:
void say()
{
std::cout << "2";
}
};
int main()
{
Child* a = new Child();
a->say();
return 0;
}
The output is 2.
So again, why would the reserved word virtual be necessary in the header of say() ?
Thanks a bunch.
If the function were virtual, then you could do this and still get the output "2":
Parent* a = new Child();
a->say();
This works because a virtual function uses the actual type whereas a non-virtual function uses the declared type. Read up on polymorphism for a better discussion of why you'd want to do this.
Try it with:
Parent *a = new Child();
Parent *b = new Parent();
a->say();
b->say();
Without virtual, both with print '1'. Add virtual, and the child will act like a Child, even though it's being referred to via a pointer to a Parent.
This is the classic question of how polymorphism works I think. The main idea is that you want to abstract the specific type for each object. In other words: You want to be able to call the Child instances without knowing it's a child!
Here is an example:
Assuming you have class "Child" and class "Child2" and "Child3" you want to be able to refer to them through their base class (Parent).
Parent* parents[3];
parents[0] = new Child();
parents[1] = new Child2();
parents[2] = new Child3();
for (int i=0; i<3; ++i)
parents[i]->say();
As you can imagine, this is very powerful. It lets you extend the Parent as many times as you want and functions that take a Parent pointer will still work. For this to work as others mention you need to declare the method as virtual.
If you do not use the virtual keyword you are not overriding, but rahter defining an unrelated method in the derived class that will hide the base class method. That is, without the virtual, Base::say and Derived::say are unrelated --besides the name coincidence.
When you use the virtual keyword (required in the base, optional in the derived class), you are telling the compiler that classes that derive from this base will be able to override the method. In that case, Base::say and Derived::say are considered overrides of the same method.
When you use a reference or pointer to a base class to call a virtual method, the compiler will add the appropriate code so that the final overrider is called (the override in the most derived class that defines the method in the hierarchy of the concrete instance in use). Note that if you do not use references/pointer but local variables, the compiler can resolve the call and it does not need to use the virtual dispatch mechanism.
Well I tested it for myself, because there are a lot of things we can think about:
#include <iostream>
using namespace std;
class A
{
public:
virtual void v() { cout << "A virtual" << endl; }
void f() { cout << "A plain" << endl; }
};
class B : public A
{
public:
virtual void v() { cout << "B virtual" << endl; }
void f() { cout << "B plain" << endl; }
};
class C : public B
{
public:
virtual void v() { cout << "C virtual" << endl; }
void f() { cout << "C plain" << endl; }
};
int main()
{
A * a = new C;
a->f();
a->v();
((B*)a)->f();
((B*)a)->v();
}
output:
A plain
C virtual
B plain
C virtual
I think that a good, simple and short answer might look like this (because I think people who can understand more can memorize less thus needing for short and simple explanation):
Virtual methods checks for the DATA of the instance the pointer points to, while classic methods don't thus calling the method correponding to the specified type.
The point of that feature is the following: suppose you have an array of A's. The array can contain B's, C's, (or even derived types.). if you want to sequentially call the same method of all those instances, you would call each one you overloaded.
I find this quite tricky to understand, and obviously any C++ course should explained how this is achieved, because most of the time you are just teached about virtual functions, you use them, but until you understand how the compiler understand them and how the executable will handle the calls, you are in the dark.
The thing about VFtables is that I have never been explained what kind of code it adds, and that's obviously here where C++ requires much more experience than C, and this might be the main reason C++ was labelled as "slow" in its early days: in fact, it's powerful, but just like everything, it's powerful if you know how to use it, or else you just "blow your whole leg off".
When you use the keyword virtual, a virtual function table is created to locate the correct methods in an instance. Then, even if the derived instance is pointed to by a base class pointer, it will still find the correct implementation of the method.
Suppose we have two classes as follows:-
class Fruit {
protected:
int sweetness;
char* colour;
//...
public:
void printSweetness() const {
cout<<"Sweetness : "<<sweetness<<"\n";
return;
}
void printColour() const {
cout<<"Colour : "<<colour<<"\n";
return;
}
virtual void printInfo() const {
printSweetness();
printColour();
return;
}
};
class Apple : public Fruit {
private:
char* genus;
//...
public:
Apple() {
genus = "Malus";
}
void printInfo() const {
Fruit::printInfo();
cout<<"Genus : "<<genus<<"\n";
return;
}
};
And now suppose we have some function like the following...
void f() {
Fruit* fruitList[100];
for(int i = 0; i<100 ; i++) {
fruitList[i]->printInfo();
}
return;
}
In cases like above, we can call the same function and rely on the Dynamic Dispatch Mechanism and the abstraction it provides without knowing what kind of fruits are stored in that array. This simplifies the code to a great deal and increases the readability. And is far far better than using type fields which makes the code ugly!
Whereas in the overridden method, we must know what kind of object we are dealing with or otherwise face the object slicing problem which may lead to unexpected results.
Note - I have written this answer just to explicitly show the benefits.
This is a very important aspect of c++ programming-- almost every interview I've been to, I get asked this question.
What happens if you change your main to:
int main() { Parent* a = new Child(); a->say(); return 0; }
Also, it's worth understanding what a vtable is.
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.