Reputation: 1002
In the code below, IContainer
is a pure abstract class: it does not contain any methods which are not pure virtual. This being the case, I don't expect to be able to instantiate an object of type IContainer
, however I do expect to be able to hold an instance of a derived class in an IContainer*
.
In main
below, I have created some instances of the concrete class SimpleContainer
which implements IContainer
. Next, I have stored a pointer to these SimpleContainer
s in some IContainer*
variables.
Here is my question: since IContainer
is an abstract class, I cannot instantiate it. However, at the bottom of my main
you can see that I dereference my IContainer
pointers in order to check equality. Why am I able to do this? Also, is there any difference between iCont1 == iCont2
and *iCont1 == *iCont2
?
#include <iostream>
class IContainer{
public:
virtual bool operator==(const IContainer& aICont) const = 0;
virtual int getVal() const = 0;
};
class SimpleContainer : public IContainer{
public:
SimpleContainer(int val) : val(val){};
int getVal() const override {return val;}
bool operator==(const IContainer& aICont) const override
{
return val == aICont.getVal();
}
private:
int val;
};
int main(){
SimpleContainer cont1(1), cont2(2), cont3(1);
IContainer* iCont1 = &cont1;
IContainer* iCont2 = &cont2;
IContainer* iCont3 = &cont3;
std::cout << "iCont1 == iCont2 -> " << (iCont1 == iCont2 ? "true" : "false") << " || Expecting -> " << "false" << std::endl;
std::cout << "*iCont1 == *iCont2 -> " << (*iCont1 == *iCont2 ? "true" : "false") << " || Expecting -> " << "false" << std::endl;
std::cout << "iCont1 == iCont3 -> " << (iCont1 == iCont3 ? "true" : "false") << " || Expecting -> " << "false" << std::endl;
std::cout << "*iCont1 == *iCont3 -> " << (*iCont1 == *iCont3 ? "true" : "false") << " || Expecting -> " << "false" << std::endl;
return 0;
}
Upvotes: 3
Views: 1623
Reputation: 1936
Remember, they are IContainer pointers, but there are not IContainers stored there. You are dereferencing your subclasses, not the parent abstract class.
SimpleContainer cont1(1), cont2(2), cont3(1);
IContainer* iCont1 = &cont1;
IContainer* iCont2 = &cont2;
IContainer* iCont3 = &cont3;
Above you create some SimpleContainers
, and you say hey, I want to reference these as IContainers since I could have other similar objects with the same parent class and I can group them together like this since my abstract class will deal with how to use the functions. This process did not change the fact that a SimpleContainer
is still stored at the same location. All your pointer is doing is saying that there is some kind of container at that location.
iCont1 == iCont2
checks if the memory location is the same for the two objects
*iCont1 == *iCont2
checks equality using your defined ==
overload.
Upvotes: 5
Reputation: 66922
You're right that you cannot have a instance of an abstract class IContainer
, but dereferencing a pointer doesn't give you an instance, it gives you a reference (IContainer&
), which is totally allowed. It is a reference to a (unspecified) derived type. Since it's a reference, you can use the dot syntax or other operators to access the methods of the interface, and it will use normal virtual lookup to find the correct overridden method to call, exactly as if it were a pointer. So yes, what you're doing works, and is safe.
Unrelated, iCont1 == iCont2
compares if two pointers (aka addresses) are equal, and *iCont1 == *iCont2
compares if two values (aka objects) are equal. Think of the first as asking if two houses have the same street address, and the second if two houses look the same. The two houses may look the same, but they'll still have different street addresses. But if two street addresses are the same, you know there's only one house involved. The two comparisons are very different from each other.
Upvotes: 6