Reputation: 113
I haven't written anything in C++ in quite some time, and am running into some inheritance issues that are confusing.
First question - From my understanding, a base class with a virtual method whose derived class implements that method should call the derived method IF the method is called from a pointer to the base class. Why does it need to be a pointer? Is this because of the way vtables are implemented? If so, why is an implementation detail not abstracted in the actual specification? I am trying to understand why this is the case. Is there a time when you want the base class to be called, only if the object is not a pointer? I thought the point was for pointers to objects to behave similarly to those objects.
Second question - In the below code, I ran a test to see that derived class methods were called if the method of access was a pointer. Then, I went back and tried to use the same method to turn the instance into a pointer to achieve the same binding. However, there is no cast that will allow me to use the class as a derived class if it was, at any point, stored as an object instance. Why is this? If, for example, I took the same objects (further below) and put them in a vector then it works correctly.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class BaseClass {
public:
virtual void A();
virtual void B();
};
void BaseClass::A() {
cout << "In base A" << endl;
}
void BaseClass::B() {
cout << "In base B" << endl;
}
class DerivedClass1 : public BaseClass {
public:
void A();
void B();
};
void DerivedClass1::A() {
cout << "In Derived A" << endl;
}
void DerivedClass1::B() {
cout << "In Derived B" << endl;
}
int main(int argc, char** argv) {
string cmd;
BaseClass bc;
DerivedClass1 dc1;
vector<BaseClass> list;
list.push_back(bc);
list.push_back(dc1);
cout << "Calling by " << endl;
for(int i = 0; i < list.size(); i++) {
// There is no possible cast to BaseClass* that causes A or B to call the derived class
(dynamic_cast<BaseClass*>(&list[i]))->A();
(dynamic_cast<BaseClass*>(&list[i]))->B();
}
// However, the below code, although it stores the same addresses, etc. works fine.
vector<BaseClass*> list_ptrs;
list_ptrs.push_back(&bc);
list_ptrs.push_back(&dc1);
cout << "Outputting Pointers" << endl;
for(int i = 0; i < list_ptrs.size(); i++) {
list_ptrs[i]->A();
list_ptrs[i]->B();
}
getline(cin, cmd);
}
Sorry if I am just misunderstanding something very basic, but it seems to be an inconsistency in the way that dynamic binding works, and I can't find a decent explanation (all Google returns are people trying to access base class methods...).
Any assistance would be appreciated, Thanks, -Alex
Upvotes: 1
Views: 308
Reputation: 35455
This is wrong:
BaseClass bc;
DerivedClass1 dc1;
vector<BaseClass> list;
list.push_back(bc);
list.push_back(dc1);
Your vector can only store BaseClass objects. Trying to stuff a DerivedClass into something that can only hold BaseClass objects is termed as object slicing
, which you do not want happen. Object slicing means just that -- you are "slicing off" the DerivedClass's attributes so that it is a BaseClass.
Either have a vector of BaseClass pointers, or two separate vectors, one of BaseClass objects, the other of DerivedClass objects.
vector<BaseClass*> theList;
theList.push_back(&bc);
theList.push_back(&dc1);
You should now see the virtual functions work as expected.
Upvotes: 4