Search code examples
c++polymorphismtypeidequivalence

Expected equivalence: typeid of data expression and type expression


I have polymorphic classes derived from a base class A:

class A {
public:
    virtual void fV() { }
};

class B : public A {
public:
    void mB() { }
};

class C : public A {
public:
    void mC() { }
};

I want now to iterate over an array pointing to such objects and check the type equivalence:

A *array[4] = { new B, new C, new C, new B };
for(int i = 0; i < 4; ++i) {
    cout << i + 1 << ". " ;
    (typeid(array[i]) == typeid(A)) ? cout << 1 << ' ': cout << 0 << ' ';
    (typeid(*array[i]) == typeid(B)) ? cout << 1 << ' ': cout << 0 << ' ';
    (typeid(*array[i]) == typeid(C)) ? cout << 1 << ' ': cout << 0 << ' ';
    cout << endl;
}

The result is:

1. 0 1 0 
2. 0 0 1 
3. 0 0 1 
4. 0 1 0 

I expect a type equivalence in the first condition, but as result I obtain a failed comparison (0 0 0 0 in the first column). The results of second and third condition are as I expected.

What is wrong with the first condition?


Solution

  • Your array is defined as A* array[4]. So the type of array[i] will be A*.

    In consequence, for the the second column (first column after index):

    • typeid(array[i]) == typeid(A) will always be false (i.e. 0 in second column)
    • typeid(array[i]) == typeid(A*) would always be true (i.e. 1 in second column)
    • typeid(*array[i]) == typeid(A) could be true if you had a new A item in your array.

    Online demo for the third case, replacing one of the derived object by an A object.

    Caution: The type equivalence that you check is a strict type equivalence. It is true only for exact matches. This means that for the second column, the test would fail for an object derived from B. Maybe this is what you're looking for and fine. But this would seriously constraint the extensibility of your polymorphic design, if your intend is just to check whether to call mB() or mC(). Alternatively you could consider using dynamic_cast<> and checking whether it returns nullptr or not