1

I want to call the child's function from parent's function in reinterpreted class, like below.

Example

#include <iostream>

class A {
public:
    void func1() {
        // some code
        func2();
        // some code
    }
protected:
    virtual void func2() {
        printf("class A\n");
    }
};

class B : public A {
protected:
    virtual void func2() {
        printf("class B\n");
    }
};

int main() {
    A* ab = new A();
    ab->func1(); // this print "class A"

    B* bab = reinterpret_cast<B*>(ab);
    bab->func1(); // this also print "class A"
    // I want to print "class B" when I use bab->func1() 
}

In this situation, Is there any way to print class B using the reinterpreted class bab without redefining func1?

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
Bonic
  • 67
  • 5
  • 2
    No you can't do that. The parent class has no idea about it's inherited classes. Why do you need this? Are you asking out of curiosity or do you have an actual use case? This sounds like an [XY Problem](https://xyproblem.info/) – Jabberwocky Nov 16 '22 at 08:35
  • 7
    Reinterpretting it as `B` and using its functions is already UB. – ALX23z Nov 16 '22 at 08:38
  • 4
    If you want to print `class B`, you need a `B` object. You did not create one anywhere, and a compiler won't either, even when you lie to it with a cast. – StoryTeller - Unslander Monica Nov 16 '22 at 08:38
  • 1
    Also read this: https://stackoverflow.com/questions/573294/when-to-use-reinterpret-cast – Jabberwocky Nov 16 '22 at 08:41
  • 1
    You can use [`static_cast`](https://en.cppreference.com/w/cpp/language/static_cast) to cast down an inheritance chain __but__ only if you can guarantee the object being cast to is of correct type (see 1st example for correct and incorrect usage). However you should prefer [`dynamic_cast`](https://en.cppreference.com/w/cpp/language/dynamic_cast) and test the result of the cast. In the code above as we don't have an object of type `B` the code has Undefined Behaviour. – Richard Critten Nov 16 '22 at 08:43
  • 2
    Don't use reinterpret_cast. Simply create a `B` and store it as a pointer to `A`. `int main() { A* ab = new B(); ab->func1(); }` prints `class B`. That's how polymorphism works in C++. That being said, don't use a naked new in 2022. It's better to create a smart pointer like `std::unique_ptr` or `std::shared_ptr`. Or you create an actual instance of `B` and create a raw pointer to A from the address of the B instance. – joergbrech Nov 16 '22 at 08:43
  • 2
    You can't, because that function was never created in the first place. Think about it: If that function would need to access values of it's class B, what should happen ? – nick Nov 16 '22 at 08:45
  • 1
    Thank you for all the comments! I need to learn more about the inheritance and casts. I think I make a wrong code at the begin. Thank you again! – Bonic Nov 16 '22 at 08:49
  • 1
    `reinterpret_cast(ab)` tells the compiler to **pretend** that `ab` is, in fact, a pointer to a `B` object. But it's not, and pretending doesn't change that. It's a pointer to an `A` object. – Pete Becker Nov 16 '22 at 18:19

1 Answers1

5

For C++ polymorphism to kick in, you must create an instance of the derived class somewhere, but you can store a pointer to the base class. Using the base-class pointer will dispatch to the overridden functions of the derived class. So your definition of A and B is fine, your usage in the main function is not. reinterpret_cast is not intended for this.

#include <iostream>
#include <memory>

class A {
public:
    void func1() {
        // some code
        func2();
        // some code
    }
protected:
    virtual void func2() {
        printf("class A\n");
    }
};

class B : public A {
protected:
    virtual void func2() {
        printf("class B\n");
    }
};

int main() {

    {
    // This works, but don't do this. Naked "new" is not modern C++ and dangerous.
    A* ab = new B();
    ab->func1();
    delete ab; 
    }

    {
    // VARIANT 2: use smart pointers
    std::unique_ptr<A> ab = std::make_unique<B>();
    ab->func1();
    }

    {
    // VARIANT 3: A non-smart pointer is okay, as long as it 
    // 1. references an existing allocated object
    // 2. the pointer does not outlive the object it points to
    B b;
    A* ab = &b;
    ab->func1();
    }

    {
    // VARIANT 4: Like Variant 3, but with reference instead of pointer
    B b;
    A& ab = b;
    ab.func1();
    }
}

Output

class B
class B
class B
class B

https://godbolt.org/z/8e5E85nx5

EDIT: Try to avoid allocation with new. Any memory allocated in this fashion must be freed by you using delete and it is very easy to forget (I did when I first wrote this answer, kinda proving my point). Even if you do delete the memory at the end of your function, there is the possibility that your code never reaches this statement, e.g. if exceptions are thrown somewhere between new and delete.Here is some further reading:

joergbrech
  • 2,056
  • 1
  • 5
  • 17
  • 2
    why is naked new not modern? why dangerous? ...because one can forget to `delete` ? ;) – 463035818_is_not_an_ai Nov 16 '22 at 08:55
  • 1
    imho the only important variant is 3. Often it is misunderstood that polymorphis would require dynamic allocation, but in fact it doesnt matter where the pointer/reference comes from. Using `new` or smart pointers is a somewhat unrelated topic – 463035818_is_not_an_ai Nov 16 '22 at 08:57
  • 1
    @463035818_is_not_a_number: Yes, among other things. You can create memory leaks very easily if you're not careful. Remember that the call of `new` might be hidden somewhere in a constructor and you have to take care of everything in the destructor for example. Then there's new/delete vs. new[]/delete[], exception handling, dangling pointers, etc... – nick Nov 16 '22 at 09:07
  • 1
    my point was just that you say "dont do it because its bad" but you dont explain what is bad but at the same time your code is an example for that bad. If a beginner reads this they dont know what is "dangerous" or why they should not use it and still may copy the code – 463035818_is_not_an_ai Nov 16 '22 at 09:09
  • @463035818_is_not_a_number haha, exactly! I am so unaccustomed to `new` that I forgot to `delete`. This comments are all very true and helpful. I will edit the answer accordingly (thnx for adding the delete in the code) – joergbrech Nov 16 '22 at 09:15
  • sorry for still nitpicking, but "Classic polymorphism in non-modern C++" no, polymorphism was always possible without `new`. Consider this function `void foo(A& a) { a.func1(); }` It is not relevant how `a` was allocated. – 463035818_is_not_an_ai Nov 16 '22 at 09:35
  • Thanks for nitpicking: It makes this answer better. This is copy-paste error from the godbolt, I changed the code comment to the one it was before. – joergbrech Nov 16 '22 at 09:53