1

i want to be sure if i understand that corectly. If i have something like that:

Base* wsk = new Derived

and if i've done that with static-binding than wsk is type of Base, but Derived type object is still created? And wsk is pointing to that Derived type object, but it cannot use methods from derived class, because wsk is Base type? To sum up the most important question for me is that if wsk except that it's Base type is still pointing to new object which is Derived type?

Tojmak
  • 155
  • 1
  • 7
  • 1
    Yes, it points to a `Derived` but you can only use `Derived` members after casting to `Derived`. I feel like any good C++ book or tutorial would make this clear pretty early. – underscore_d Jul 30 '20 at 09:37
  • 1
    Of course any virtual methods that exist in `Derived` can be used without casting. – john Jul 30 '20 at 09:44
  • 1
    @john "any virtual methods of `Base` that `Derived` overrides" – Caleth Jul 30 '20 at 09:45

2 Answers2

3

One big remark, as mentioned above, when looking at Base * it point to type Base. I'm not using this notation in order to simplify the explanation.

What you are asking is a different question: what is the difference between the static type and the dynamic/runtime type of an object.

Let's observe the following code:

#import <iostream>

class Base
{
    public:
    virtual void foo()
    {
        std::cout << "From Base" << std::endl;
    }
};

class A : public Base
{
    public:
    void foo() override
    {
        std::cout << "From A" << std::endl;
    }

    void some_A_only_function()
    {
        std::cout << "some function from A" << std::endl;
    }
};

class B : public Base
{
    public:
    void foo() override
    {
        std::cout << "From B" << std::endl;
    }

    void some_B_only_function()
    {
        std::cout << "some function from B" << std::endl;
    }
};


int main()
{
    Base base{};
    Base * a = new A();
    Base * b = new B();

    base.foo();

    a->foo();
    // a->some_A_only_function(); this won't compile: error: no member named 'some_A_only_function' in 'Base'

    b->foo();
    // b->some_B_only_function(); this won't compile either!!
}

And the output is:

From Base

From A

From B

All the objects here are from a static type of Base, thus, you cannot call any function that isn't part of Base, since the compiler cannot know which type is put in there in runtime. If we have overridden functions, the appropriate one will be called according to the runtime type (this is called dynamic dispatch).

To sum it up, there are 3 objects here:

  1. An object of static type Base and dynamic type Base.
  2. An object of static type Base and dynamic type A.
  3. An object of static type Base and dynamic type B.

The only way to use the functions of A or B respectively, is by using casting in order to "return" them into their original form. But it should be done with caution!

Big remark: This is actually true in any language that offers polymorphism (as far as I know). It isn't unique to C++!

Kerek
  • 1,106
  • 1
  • 8
  • 18
  • Nitpick: there are also 2 objects of type `Base *`, and there were materialised temporaries of type `A *` and `B *` – Caleth Jul 30 '20 at 09:56
  • @Caleth Indeed I have made over-simplification in order to address the core of the question, added a comment about that :) – Kerek Jul 30 '20 at 09:58
  • 1
    @Kerek i'm still thinking that my question is correct, but your answer help to clarify that what Caleth is mentioned. Thanks for that. – Tojmak Jul 30 '20 at 10:04
2

wsk is of type Base *, not Base nor Derived.

It was initialised with a value that was (implicitly) converted from type Derived *. It points to a Base object, which so happens to reside within a Derived object.

That means that static_cast<Derived *>(wsk) will give you a value that points to a Derived.

It may be that the representation of wsk is the same number as the representation of static_cast<Derived *>(wsk), i.e. that the address of the Base object is the same as the address of the Derived object, but that is not guaranteed

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • *It points to a Base object, which so happens to reside within a Derived object.* - wsk (here) points to an object of type Derived. – Swordfish Jul 30 '20 at 09:43
  • @Swordfish No, it points to the `Base` base sub-object of a `Derived` object – Caleth Jul 30 '20 at 09:44
  • There is no "sub-object". If you wish to argue in that direction bring reference. – Swordfish Jul 30 '20 at 09:45
  • 1
    @Swordfish "Each direct and indirect base class is present, as base class subobject, within the object representation of the derived class at implementation-defined offset." [derived class on cppreference](https://en.cppreference.com/w/cpp/language/derived_class) – Caleth Jul 30 '20 at 09:46
  • @Swordfish Consider multiple inheritance and virtual base classes: if every derived instance always had the same address as its base, those would simply not be possible. – underscore_d Jul 30 '20 at 09:49
  • 1
    @Swordfish or "Objects can contain other objects, called subobjects. A subobject can be a member subobject ([class.mem]), a base class subobject ([class.derived]), or an array element." [`[intro.object]`](https://timsong-cpp.github.io/cppwp/n4861/intro.object#2) – Caleth Jul 30 '20 at 09:50