C++;虚函数的多态性 我试图找出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; }

C++;虚函数的多态性 我试图找出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; },c++,function,inheritance,polymorphism,virtual,C++,Function,Inheritance,Polymorphism,Virtual,您需要将左和右设置为Expr*或Expr&,而不是Expr 不同于java,C++中的类类型的变量保存实际实例,而不是引用实例。 所以当你这样做的时候: Expr left = term(); 实际上,您正在调用Expr的复制构造函数,它将只生成基本Expr类的一个实例 在Java中,这是非常不同的——您只是将left设置为引用某个现有对象,而不是创建一个新对象 p> >需要左 >代码>右,以使在C++中使用的同样的事情发生在java中。 < p>需要生成左< />代码> 右> />代码>

您需要将
设置为
Expr*
Expr&
,而不是
Expr

不同于java,C++中的类类型的变量保存实际实例,而不是引用实例。

所以当你这样做的时候:

Expr left = term();
实际上,您正在调用
Expr
的复制构造函数,它将只生成基本
Expr
类的一个实例

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


<> p> >需要<代码>左<代码> >代码>右<代码>,以使在C++中使用的同样的事情发生在java中。

< p>需要生成<代码>左< />代码> <代码>右> />代码> be >代码> ExpR*<代码>或<代码> ExpR& < /> >,而不是<代码> EXPR < < /P>

不同于java,C++中的类类型的变量保存实际实例,而不是引用实例。

所以当你这样做的时候:

Expr left = term();
实际上,您正在调用
Expr
的复制构造函数,它将只生成基本
Expr
类的一个实例

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


因此,需要有<代码>左< /> >和>代码>右<代码>,否则,在C++中发生的事情与java中相同的事情发生了。

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

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

您的问题从以下代码开始:

Expr Prefixer::term()
{
    NullExpr temp;
    return temp;
}
temp
是一个局部变量,在函数结束时销毁。返回值通过复制返回表达式
temp
生成一个
Expr
实例(因为这是返回类型)。调用方从未看到
NullExpr
对象

Java的基本功能是:

Expr* Prefixer::term()
{
    NullExpr* temp = new NullExpr;
    return temp;
}
<>但是你不能盲目地在C++中做这件事,否则你会被内存泄漏(java有垃圾回收器,C++没有)。您可以使用
删除
释放内存:

Expr* left = term();
left->name();
delete name;
更推荐的方法是使用智能指针,当指向对象的最后一个指针消失时自动销毁该对象:

shared_ptr<Expr> Prefixer::term()
{
    NullExpr* temp = new NullExpr;
    return temp;
}
shared_ptr Prefixer::term()
{
NullExpr*temp=新的NullExpr;
返回温度;
}

您的问题从以下代码开始:

Expr Prefixer::term()
{
    NullExpr temp;
    return temp;
}
temp
是一个局部变量,在函数结束时销毁。返回值通过复制返回表达式
temp
生成一个
Expr
实例(因为这是返回类型)。调用方从未看到
NullExpr
对象

Java的基本功能是:

Expr* Prefixer::term()
{
    NullExpr* temp = new NullExpr;
    return temp;
}
<>但是你不能盲目地在C++中做这件事,否则你会被内存泄漏(java有垃圾回收器,C++没有)。您可以使用
删除
释放内存:

Expr* left = term();
left->name();
delete name;
更推荐的方法是使用智能指针,当指向对象的最后一个指针消失时自动销毁该对象:

shared_ptr<Expr> Prefixer::term()
{
    NullExpr* temp = new NullExpr;
    return temp;
}
shared_ptr Prefixer::term()
{
NullExpr*temp=新的NullExpr;
返回温度;
}

是的。按值而不是指针或引用返回会导致将对象“切片”到基类型中,派生类型将丢失。不仅需要更改局部变量,还需要更改返回值以避免切片。这意味着还引入了动态分配。感谢您的帮助!我现在知道问题的根源了。但是,如果我将Expr的值传递给left和right,如何使用left和right调用name()函数?现在我得到一个类似这样的错误:错误:请求成员?名称?在非类类型(Expr*)@Jason的?left?中:要访问指针的成员,请使用
->
。像
left->name()
。还有一些其他的方法。例如,可以使用保存值的容器,并在复制时从其派生类型复制该值。就是这样一个容器。您还可以使用一个容器来保存
base*
,并调用一个虚拟的
duplicate
函数来copy.Yep。按值而不是指针或引用返回会导致将对象“切片”到基类型中,派生类型将丢失。不仅需要更改局部变量,还需要更改返回值以避免切片。这意味着还引入了动态分配。感谢您的帮助!我现在知道问题的根源了。但是,如果我将Expr的值传递给left和right,如何使用left和right调用name()函数?现在我得到一个类似这样的错误:错误:请求成员?名称?在非类类型(Expr*)@Jason的?left?中:要访问指针的成员,请使用
->
。像
left->name()
。还有一些其他的方法。例如,您可以使用保存值的容器,并从其派生类型复制它