Hi, been a while since I posted here. Learning C++ has been getting easier.
Anyway, there's a program which will use virtual functions in order to make sure the right function is called. However, the virtual function wont work without using the "&" in the parameter of the caller function.
The "void report(Animal &animal)" function (right over int main()) is the one I'm talking about. Take away the "&" and the output will be "???" from the speak() function in the base class. However, I don't really understand what the "&" does in order to allow the code to correctly print "meow" and "woof". Any information is appreciated, thanks!
EDIT:
An add-on question that is also related. Using the same program as above (But with a different int main()), this code will work.
1 2 3 4 5 6 7 8 9 10
int main()
{
Cat fred("Fred"), misty("Misty"), zeke("Zeke");
Dog garbo("Garbo"), pooky("Pooky"), truffle("Truffle");
// Set up an array of pointers to animals, and set those pointers to our Cat and Dog objects
Animal animals[] = { fred, garbo, misty, pooky, truffle, zeke };
for (int iii = 0; iii < 6; ++iii)
std::cout << animals[iii].getName() << " says " << animals[iii].speak() << '\n';
}
HOWEVER, this code will also work.
1 2 3 4 5 6 7 8 9 10
int main()
{
Cat fred("Fred"), misty("Misty"), zeke("Zeke");
Dog garbo("Garbo"), pooky("Pooky"), truffle("Truffle");
// Set up an array of pointers to animals, and set those pointers to our Cat and Dog objects
Animal *animals[] = { &fred, &garbo, &misty, &pooky, &truffle, &zeke };
for (int iii = 0; iii < 6; ++iii)
std::cout << animals[iii]->getName() << " says " << animals[iii]->speak() << '\n';
}
The difference between these two is that "animals" array is a pointer. The one where it is a pointer is the example given in the tutorial, but my weak point is with pointers and such. Is the first example without a pointer less optimized than the one with the pointers?
The "&" and "*" functions work together and are closely related (which is why I didn't make a new question). So if someone could explain the significance of these symbols in the examples given, it would greatly help me as I continue learning C++. Thanks!
In order to get virtual function dispatch you need to call the function through a pointer or a reference (a kind of simplified pointer that you use like it isn't a pointer). The & in the parameter creates a "reference" parameter.
As for your second question, what makes you think the first one works? It doesn't. To get virtual function dispatch you need to use a pointer or a reference. The * means that animals stores Animal pointers and the & evaluates to the address of the object it prefixes.
Thanks for telling me that. I made the first one to see if it would work without a pointer. When I first compiled it, it worked. I guess the Visual Studio didn't compile the new code.
I suppose I should also delve deeper into my question as well. I can see now that without pointers/references that the virtual function wont dispatch. However, I don't understand what is truly happening that allows for that. The "animals" pointer is an array that stores many referenced derived classes. The "&" evaluates to the memory addresses of those derived classes, I understood that. The "*" itself makes "animals" store the memory addresses of the now referenced variables. However, how does having the memory address of these variables contribute to the virtual function dispatching?
Sorry if I'm asking too much, information on the internet doesn't really answer these questions. Thanks for the reply tpb!
Consider a derived class without virtual functions:
1 2 3 4 5 6 7
class Base {
int a, b;
};
class Derived : public Base {
int c, d;
};
A Base object will have an a and b. A Derived object will have an a, b, c, and d. So they will look like this:
A Base object:
a
b
A Derived object:
a
b
c
d
If Derived is passed as a Base then only a and b will be copied; the c and d will be "sliced" off. But if you pass a pointer then the whole object can be accessed through the pointer.
Each CLASS with virtual functions has something called a "virtual function table" (or "vtable") which is a table of pointers to the functions. When a class is derived from a class with virtual functions, it duplicates the vtable and updates the entries with it's own pointers for any functions that it overrides. Each OBJECT of a class with a vtable has an extra (hidden) member (vptr) that points to the vtable. Virtual functions are called through this pointer.
A Base object:
vptr (to Base's vtable)
a
b
A Derived object:
vptr (to Derived's vtable)
a
b
c
d
Therefore the main problem with trying to call a Derived class's virtual function override through a Base class copy of that object is that you probably don't even have the entire Derived object since only the Base class part of it would be copied. So even if the virtual function table pointer is the first member in the object (which it may not be but if it is then you would have the correct pointer to the derived class's virtual function override), some of the object may have been "sliced" off, so it's not a trustworthy action to call that function since it may need some of the missing members. Instead, the base class function is called as a regular function call (not as a virtual function).
Thanks tpb for that explanation, it was thorough and easy to follow/understand.
If Derived is passed as a Base then only a and b will be copied; the c and d will be "sliced" off. But if you pass a pointer then the whole object can be accessed through the pointer.
So let me make sure I understood correctly. Virtual functions will NOT be called if variables aren't passed as a pointer. This is because copying a derived function to a base one could lead to certain objects/variables, that it may need, not being copied. However, a pointer holds the memory addresses and isn't "copied" or altered. Instead, the pointer will be pointing to the memory addresses of the derived classes which contain all the needed variables and then the pointer itself is used rather than copied (I assume). This now insures that the variables needed will definitely be there so the virtual function will be called as such.
Correct me and let me know if this is correct or not. I hope I at least got the basic concept of this. Thanks again tpb, you're a huge help.
Yes. A by value function argument is a copy, but a by reference argument is a reference to caller's object.
1 2
Derived foo;
Base bar = foo;
The bar is different object than the foo. The bar object has type Base. It is not a Derived, even though the "Base" object that was used to initialize (copy construct) the bar is more than "just a Base".
By value function arguments are copy constructed, just like the bar above.
1 2 3
Derived foo;
Base& gaz = foo;
gaz.fubar();
The gaz is a reference. The member fubar() of object foo is thus called. The foo IS-A Derived.
Thanks for letting me know tpb. Also, thanks keskiverto for the clarification as well, it was helpful to get a deeper insight.
So basically, the animals pointer holds the derived member's memory addresses. So because there are the derived classes that are passed in (through the pointer) which evaluate to memory addresses, the virtual function is called. Which is why the example I gave without pointers or "&" wouldn't work, and why the first example needs to have Animal &animal to work.
Thanks again guys for the help. After this, pointers and such don't seem as difficult as they first seemed to be (I vowed I'd stay away for as long as I could manage without them!). I really appreciate it!