【问题标题】:Reference and pointer in polymorphism多态中的引用和指针
【发布时间】:2015-10-26 15:26:44
【问题描述】:

基础抽象类:

class Satellite
{
public:
    Satellite();
    virtual void center()=0;
    virtual ~Satellite(){}
};

第一个派生类

class Comm_sat:public Satellite
{
public:
    Comm_sat();
    void center() override{cout << "comm satellite override\n";}
};

第二个派生类

class Space_station:public Satellite
{
public:
    Space_station();
    void center() override{cout << "space station override\n";}
};

函数的指针版本

void f(Satellite* ms){
    ms->center();
    delete ms;
}

int main()
{
    Comm_sat* cs = new Comm_sat;
    Space_station* ss = new Space_station;
    f(cs);
    f(ss);
}

main() 中使用new 创建的对象在f() 中被正确销毁,对吧?

函数的参考版本

void f(Satellite& ms){
    ms.center();
}

int main()
{
    Comm_sat cs;
    Space_station ss;
    f(cs);
    f(ss);
}

参考版更好吗?

此外,我尝试使用unique_ptr,但是,我得到了错误

void f(Satellite* ms){
    ms->center();
}

int main()
{
    unique_ptr<Comm_sat> cs{new Comm_sat};
    unique_ptr<Space_station> ss{new Space_station};
    f(cs);
    f(ss);
}

错误:无法将 std::unique_ptr&lt;Comm_sat&gt; 转换为 Satellite* 以将参数 1 转换为 void f(Satellite*)
错误:输入class std::unique_ptr&lt;Comm_sat&gt; 参数给delete,预期指针delete cs

另一个派生类也出现同样的错误。

【问题讨论】:

  • void main 是不允许的。

标签: c++ pointers reference polymorphism


【解决方案1】:

参考版更好吗?

是的,虽然更好的说法是“指针版本更差”。指针版本的问题是你传递了一个有效的指针,并在函数返回时得到一个悬空指针。这不直观,当有人修改您的代码时认为您忘记删除main 中的csss,而没有意识到f 删除了它的参数时,这会导致维护问题。

使用引用的版本在这方面要好得多,因为资源是自动为您管理的。您的代码的读者不需要跟踪csss的内存被释放的地方,因为分配和释放是自动发生的。

我尝试使用unique_ptr,但出现错误

没有从std::unique_ptr&lt;T&gt;T* 的隐式转换。如果你想传递一个原始指针,你需要调用get()

f(cs.get());
f(ss.get());

【讨论】:

  • 如果我理解正确,在任何一种情况下(指针或引用),对象都是在堆上分配的,而不是在堆栈上,对吧?
  • @MiloLu 使用引用的版本在堆栈上同时分配csss 对象。
  • 正如无用的建议,我可以在堆上分配对象,并且仍然通过引用传递*cs*ss。在我看来,地址只是一个地址,不管它是在堆上还是在栈上。
  • @MiloLu 这取决于你。在堆栈上分配的一个优点是您不需要跟踪对象的生命周期并调用delete。堆栈分配的缺点是,您无法将对象的生命周期延长到其被分配的块的运行时间之后。
  • 除此之外,堆栈比堆快,这又使参考版本更受欢迎?
【解决方案2】:

main() 中使用new 创建的对象在f() 中被正确销毁,对吧?

它们已被销毁并正确清理,是的。不过,“正确地”是一个延伸,因为所有这些手动新建和删除原始指针的东西都是糟糕的风格。

unique_ptr 不适合您的原因是......它是一个unique_ptr,而不是原始指针。您不能将其作为原始指针传递。

试试

void f(Satellite* ms){
    ms->center();
}
// ...
f(cs.get());

或者更好,除非你有时真的需要传递nullptr

void f(Satellite& ms){
    ms.center();
}
// ...
f(*cs);

或者最重要的是,因为您根本没有任何理由需要动态分配:

void f(Satellite& ms);
// ...
{
    Comm_sat cs;
    f(cs);
} // no new, no delete, cs goes out of scope here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-13
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-19
    • 2015-04-21
    • 2018-04-21
    相关资源
    最近更新 更多