1

我试图弄清楚 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";
}
4

3 回答 3

4

你需要做leftrightExpr*Expr&,不是Expr

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

所以当你这样做时:

Expr left = term();

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

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

因此,需要拥有leftright成为引用或指针——这样在 C++ 中就会发生与在 Java 中发生的事情相同的事情。

于 2012-05-28T03:22:28.657 回答
2

您的问题始于以下代码:

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

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

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;
}
于 2012-05-28T03:26:52.517 回答
0

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

于 2012-05-28T03:24:01.483 回答