wesanyer
wesanyer

Reputation: 1002

Why am I able to dereference a pointer to an abstract class?

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 SimpleContainers 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

Answers (2)

Easton Bornemeier
Easton Bornemeier

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

Mooing Duck
Mooing Duck

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

Related Questions