1
struct Foo{
    Foo(int val) : i(val){}

    Foo &operator=(const Foo&){ //... }

    void fun(){}

    int i;
    std::string s;
};

struct Bar : public Foo{
    Bar(int i) : Foo(i){}

    Bar &operator=(const Bar &other){ 
        this->Foo::operator=(other);
        return *this;
    }

    void new_func(){}
}

Take this piece of code for example, Bar is extended version of Foo, and no additional member variables are added. Any danger downcasting a Foo instance to Bar, and use the extended function?

Also, is there a way to allow me downcast Foo to Bar implicitly, so I don't have to write static_cast all the time?

Theo Mars
  • 41
  • 4
  • 1
    No, it's not safe to cast an object to a type that it isn't. And why do you want to do this in the first place? – UnholySheep Apr 13 '22 at 15:35
  • in case it's only added methods in the derived class, why not add it to the base class in the first place? And remember, [inheritance is the base class of evil](https://www.youtube.com/watch?v=bIhUE5uUFOA) ;) – codeling Apr 13 '22 at 15:39
  • @UnholySheep I want to extend a class from a thirdparty library, with new functionality. And the original class is used all over the place. I want to keep them untouched, and only use the extended class, in the new code. I'm relative new to to c++, can you tell me a why it is unsafe? A key word is ok, I'll learn about it. – Theo Mars Apr 13 '22 at 15:40
  • @codeling I want to extend a class from a thirdparty library without touching the original codes. – Theo Mars Apr 13 '22 at 15:42
  • 5
    Instead of extending by inheritance, consider extending by wrapping `struct Bar { Foo& foo; ...}` or extending by free-standing functions `void new_func(Foo&);` – Eljay Apr 13 '22 at 15:42
  • It's my ignorant hypothesis, but probably compiler stores a table for each class with pointers to methods. If a method comes from the base class, both child and base classes will have the same pointer value for the method. Since you only call Foo's methods, all the pointers are the same. So with some probability there shouldn't be direct danger. But UB is UB – Alexey S. Larionov Apr 13 '22 at 15:43
  • @TheoMars It is unsafe because it causes undefined behaviour and makes your entire program invalid. If it appears to work, it's just bad luck. – molbdnilo Apr 13 '22 at 15:44
  • You shouldn't do it as it's very naughty and not standard C++. That said, Microsoft's implementation of the Component Object Model pretty much relies on it (see CComVariant). Personally I wouldn't push my luck. Build a class with `Foo` as a member instead. – Bathsheba Apr 13 '22 at 15:58

2 Answers2

3

Any danger downcasting a Foo instance to Bar, and use the extended function?

If the instance manipulated was created as a Bar, upcasted to a Foo, and then downcasted back to a Bar, all is well.

If you take an instance constructed as a Foo and downcast it to a Bar, you're both feet in Undefined Behaviour territory.


Is there a way to allow me downcast Foo to Bar implicitly

No, fortunately no. By design. But you can create a Bar from a Foo provided Bar has a copy constructor taking a Foo.


I want to extend a class from a thirdparty library, with new functionality. And the original class is used all over the place. I want to keep them untouched, and only use the extended class, in the new code

Inheritance is not the paradigm you are looking for. enter image description here You're looking for something simpler like composition.

YSC
  • 38,212
  • 9
  • 96
  • 149
1

Any danger downcasting a Foo instance to Bar, and use the extended function?

It's safe only if the Foo instance is an ancestor sub object of a Bar instance. In any other case the behaviour of the program is undefined.

If you were to add a virtual function into Foo, then it would be safe to attempt dynamic cast, but it would fail in the latter case.

Also, is there a way to allow me downcast Foo to Bar implicitly

No.

eerorika
  • 232,697
  • 12
  • 197
  • 326