簡體   English   中英

C ++中的覆蓋函數不起作用

[英]Overriding function in C++ doesn't work

#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();
}

這個問題很簡單:為什么a->func()調用類的函數A即使a包含B類的對象?

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

以下是此代碼中一步一步發生的情況:

  • new B() :在免費商店中分配類型B的新對象,從而生成其地址
  • (A*) :對象的地址被強制轉換為A* ,因此我們有一個類型為A*的指針實際指向類型為B的對象,該對象是有效的。 一切都好。
  • A a :這里問題就出現了。 在堆棧上創建類型A的新本地對象 ,並使用復制構造函數A::A(const A&)構造,第一個參數是之前創建的對象。
  • 在此語句之后,指向類型B的原始對象的指針將丟失,從而導致內存泄漏,因為它是使用new分配在免費存儲上的。
  • a.func() - 在A類的(本地)對象上調用該方法。

如果您將代碼更改為:

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

然后只構造一個對象,它的指針將轉換為A*類型A*指針,然后解除引用,並用該地址初始化一個新的引用 然后,虛函數的調用將動態解析為B::func()


但請記住,您仍需要釋放該對象,因為它已分配給new

delete &a;

順便說一句,如果A有一個虛擬的析構函數,那將是正確的,這需要B ::〜B()(幸運的是這里是空的,但在一般情況下它不需要)也將是調用。 如果A沒有虛擬析構函數,那么您需要通過以下方式釋放它:

delete (B*)&a;

如果您想使用指針,那么與引用相同。 碼:

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.

您遇到的問題是經典對象切片

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

a一個引用或指向A指針,虛擬調度將按預期工作。 有關更多解釋,請參閱此其他問題


您評論了另一個答案,“編譯器至少應該發出警告或者什么”。 這就是為什么將基類設為非可復制的抽象被認為是一種好的做法:您的初始代碼不會首先編譯。

現在您已修改了代碼段,問題很明顯。 多態性(即虛函數)僅通過指針和引用調用。 你沒有這些。 A a = XXX不包含類型B的對象,它包含類型A的對象。 您通過執行指針轉換和取消引用來“切掉”對象的B度。

如果你做A *a = new B(); ,那么你將得到預期的行為。

這可能就是這個伎倆。

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

要么

A *a = new B();
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 = new B();
  a->func();
}

問題是使用A a = *(A *)new B()將B與A一起推向A:

您可以通過刪除*(A *)將其更改為(A * a = new B();)來修復它,但我會更進一步,因為您的變量名稱不適合B的實例化。

它應該是

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

因為在將動態分配的對象復制到類型A對象a (這也給了您內存泄漏)時執行了切片。

a應該是引用( A& ),或者只是保留指針。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM