开发者

Overriding function in C++ doesn't work

开发者 https://www.devze.com 2023-02-01 19:51 出处:网络
#include <cstdio> using namespace std; class A { public: virtual void func() { printf(\"A::func()\"); }
#include <cstdio>
using namespace std;

class A {
public:
    virtual void func() { printf("A::func()"); }
};

class B : public A {
public:
    virtual void func() { printf("B::func()"); }
};

int main() {
  A a = *(A *)new B();
  a.func();
开发者_运维百科}

The question is simple: why a->func() calls function in class A even though a contains object of class B?


A a = *(A *)new B();
a.func();

Here's what happens in this code, step by step:

  • new B(): a new object of type B is allocated on the free store, resulting in its address
  • (A*): the address of the object is cast to A*, so we have a pointer of type A* actually pointing to an object of type B, which is valid. All OK.
  • A a: here the problems start. A new local object of type A is created on the stack and constructed using the copy constructor A::A(const A&), with the first paremeter being the object created before.
  • The pointer to the original object of type B is lost after this statement, resulting in a memory leak, since it was allocated on the free store with new.
  • a.func() - the method is called on the (local) object of class A.

If you change the code to:

A& a = *( A*) new B();
a.func();

then only one object will be constructed, its pointer will be converted to pointer of type A*, then dereferenced and a new reference will be initialized with this address. The call of the virtual function will then be dynamically resolved to B::func().


But remember, that you'd still need to free the object since it was allocated with new:

delete &a;

Which, by the way, will only be correct if A has a virtual destructor, which is required that B::~B() (which luckily is empty here, but it doesn't need to in the general case) will also be called. If A doesn't have a virtual destructor, then you'd need to free it by:

delete (B*)&a;

If you would want to use a pointer, then that's the same as with the reference. Code:

A* a = new B(); // actually you don't need an explicit cast here.
a->func();
delete (B*)a; // or just delete a; if A has a virtual destructor.


Now that you've modified your code snippet, the problem is clear. Polymorphism (i.e. virtual functions) are only invoked via pointers and references. You have neither of these. A a = XXX does not contain an object of type B, it contains an object of type A. You've "sliced away" the B-ness of the object by doing that pointer cast and dereference.

If you do A *a = new B();, then you will get the expected behaviour.


The problem you encounter is classic object slicing :

A a = *(A *)new B();

Make a either a reference or pointer to A, and virtual dispatch will work as you expect. See this other question for more explanations.


You commented on another answer that "Compiler should at least give warning or what". This is why is it considered a good practice to make base classes either abstract of non copyable : your initial code wouldn't have compiled in the first place.


This might do that trick.

A &a = *(A *)new B();
a.func();

Or

A *a = new B();
a->func();


Virtual dispatch works only with pointer or reference types:

#include <cstdio>
using namespace std;

class A {
public:
  virtual void func() { printf("A::func()"); }
};

class B : public A {
public:
  virtual void func() { printf("B::func()"); }
};

int main() {
  A* a = new B();
  a->func();
}


The problem is the deference and casting of B to A with the A a = *(A *)new B();

You can fix it with just removing the *(A *) changing it to (A *a = new B(); ) but I would take it a step further since your variable name is not good for instantiation of B.

It should be

B *b = new B(); 
b->func(); 


Because you performed slicing when you copied the dynamically allocated object into object a of type A (which also gave you a memory leak).

a should be a reference (A&) instead, or just keep the pointer.

0

精彩评论

暂无评论...
验证码 换一张
取 消