C++ 虚函数的多态性

C++ Polymorphism on Virtual Functions

本文关键字:多态性 函数 C++      更新时间:2023-10-16

我试图弄清楚在C++中如何处理继承和多态性,它似乎与我在 Java 中习惯的有点不同。我正在尝试在其中一个函数中返回一个基类,但是当收到返回时,我希望该对象是派生类。但是,它并没有像我预期的那样工作。

#include "Prefixer.h"
using namespace std;
Prefixer::Prefixer( Lexer l ){
    lexer = l;
}
Expr Prefixer::expr() {
    Expr left = term();
    Expr right = termTail();
    cout << left.name();
    cout << right.name();
    return left;
}
Expr Prefixer::term() {
    NullExpr temp;
    return temp;
}
Expr Prefixer::termTail() {
    NullExpr temp;
    return temp;
}

但是返回的 left.name() 和 right.name() 都调用 Expr(基类)的虚拟 name() 函数 :C。我怎样才能使它们从派生类 NullExpr 调用重载的 name() 函数?

string Expr::name() {
    return "expr";
}
string NullExpr::name() {
    return "null";
}

你需要使leftright Expr*Expr&,而不是Expr

与 Java 不同,类类型的变量C++保存实际实例,而不是对实例的引用。

因此,当您这样做时:

Expr left = term();

您实际上是在调用Expr的复制构造函数,该构造函数只会创建基Expr类的一个实例。

在Java中,这是非常不同的 - 你只是设置left引用一些现有的对象,而不是创建一个新的对象。

因此,需要有leftright是引用或指针 - 以便在你习惯于在Java中发生的C++中发生同样的事情。

您的问题始于以下代码:

Expr Prefixer::term()
{
    NullExpr temp;
    return temp;
}

temp是一个局部变量,在函数结束时销毁。 返回值通过复制返回表达式temp 来创建一个Expr实例(因为这是返回类型)。 调用方永远不会看到NullExpr对象。

Java所做的本质上是:

Expr* Prefixer::term()
{
    NullExpr* temp = new NullExpr;
    return temp;
}

但是你不能盲目地在C++中这样做,否则你最终会得到内存泄漏(Java有一个垃圾收集器,C++没有)。 您可以使用以下方法释放内存delete

Expr* left = term();
left->name();
delete name;

更推荐的方法是使用智能指针,当指向对象的最后一个指针消失时,它会自动销毁对象:

shared_ptr<Expr> Prefixer::term()
{
    NullExpr* temp = new NullExpr;
    return temp;
}

要使用方法dynamic-binding(或使用基对象的句柄调用重载子类方法),您应该使用引用或指针操作对象。如果这样实现,请确保返回对象的生存期足够长,以便在方法终止后可以访问它。你会发现它与Java不同,因为Java中的所有对象确实是对堆上存储的引用,而不是对象本身。