【问题标题】:call parent virtual function from child class从子类调用父虚函数
【发布时间】:2015-09-09 19:29:12
【问题描述】:

我想用两个“单位”做一些“决斗”。 我编写了由两个“单元”构成的类“决斗”。 但是某种“单位”是特殊的(继承自单位),如英雄、boss等。他们想在战斗中使用特殊打击。 但实际上“决斗”类不知道谁是英雄,谁是纯单位。

代码如下:

#include <iostream>

class unit{
  public:
   unit(){};
   virtual void make_hit(){
     std::cout<<"pure hit\n";
   }
};

class hero:public unit {
  public:
   hero():unit(){};
   void  make_hit(){
     std::cout<<"SUPER hit\n";
   }
};

class duel {
  unit *a, *b;
  public:
  duel(unit _a, unit _b):a(&_a),b(&_b){};
  void start (){
    a->make_hit();
    b->make_hit();
  }
};

int main(){
  duel(unit(),hero()).start();
  return 0;

}

我有两个主要问题。

首先 - 我使用的是指构造函数中的临时对象。当 Duel::duel() 完成时,该对象是非法的。

第二个——我的英雄变成了纯粹的单位,不使用“超级命中”

是否有可能以优雅的方式修复它(无需更改main() 中的调用)?

【问题讨论】:

  • IIRC,您传递的是您创建的对象的副本,而不是原始对象。并且副本是由 param 变量定义的类型。见cplusplus.com/forum/windows/9891
  • 在不更改main() 中的调用的情况下,没有优雅的方法可以修复它。对不起。
  • 好的,我知道没有引用或指针构造函数将对象切割成单元对象。谢谢。
  • 理论上,你可以使用右值引用(unit&amp;&amp;)。但是,这会带来寿命问题。在你写的代码中,这不会有问题,但是如果你使用临时构建一个对决,然后再使用它,那就有问题了。

标签: c++ class polymorphism


【解决方案1】:

由于切片,最好始终将多态性与 智能指针。这是一个可能的设计:

#include <iostream>
#include <memory>
#include <utility>

using namespace std;

class unit_base
{
public:
    virtual ~unit_base() = default;
    virtual void make_hit() =0;
};

class unit : public unit_base
{
public:
    unit() = default;
    virtual void make_hit() override
    {
        cout << "pure hit" << endl;
    }
};

class hero : public unit_base
{
public:
    hero() = default;
    virtual void make_hit() override
    {
        cout << "SUPER hit" << endl;
    }
};

class duel
{
public:
    duel( shared_ptr<unit_base> a, shared_ptr<unit_base> b )
        : a(a), b(b)
    {}
    void start()
    {
        auto aa = a.lock();
        auto bb = b.lock();
        if( aa && bb )
        {
            aa->make_hit();
            bb->make_hit();
        } else {
            cout << "duelist expired" << endl;
        }
    }
private:
    weak_ptr<unit_base> a, b;
};

int main()
{
    // use with temporarys
    duel{ make_shared<unit>(), make_shared<hero>() }.start();

    cout << "-------------" << endl;

    // use with variables
    auto u = make_shared<unit>();
    auto h = make_shared<hero>();
    duel d{h,u};
    d.start();

    cout << "-------------" << endl;

    // try to use with expired duelists
    u.reset();
    d.start();
}

还记得在你的基类中始终有一个虚拟析构函数。

【讨论】:

    【解决方案2】:

    duel(unit _a, unit _b):a(&_a),b(&_b){};
    

    在传递值时,您正在对对象进行切片。要解决这个问题,您可以在构造函数中使用指针

    duel(unit* _a, unit* _b):a(_a),b(_b){};
    

    然后您需要更改main() 以创建对象并将它们传递给duel

    int main(){
        unit npc;
        hero bob;
        duel d(&npc,&bob);
        d.start();
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      我在 C++ 中为自己找到的唯一方法是在“决斗”类中进行所有构造函数的组合。这个解决方案不是那么优雅,在添加新类时需要更改“决斗”代码,而且这也有开销。

        ~duel(){
          delete a;
          delete b;
        }
      #define _cc(t1, t2) duel(t1 _a, t2 _b) : a(new t1 (_a)), b (new t2(_b)){}
        _cc(unit,unit);
        _cc(hero,unit);
        _cc(unit,hero);
        _cc(hero,hero);
      #undef _cc
      

      我也尝试过为此使用模板,但我找不到自动确定类型的方法。

      【讨论】:

      • templated version 也不漂亮
      • 这对我来说真的很好看。我印象非常深刻。我无法理解所有代码,但我会尽力理解。
      猜你喜欢
      • 2010-09-18
      • 1970-01-01
      • 2019-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多