【问题标题】:c++ polymorphism and passing subclasses aroundc ++多态性和传递子类
【发布时间】:2015-05-12 15:10:42
【问题描述】:

我正在研究 C++ 中的继承,并尝试实现一个基本设置,其中 基类具有 a) 子类必须实现的抽象方法 fire() 和 b) 子类继承的变量 someDouble

我当前的设置如下。这不会编译,因为getDerivedObject() 正试图返回一个抽象类。 (请注意,如果可能的话,为了安全起见,我宁愿保留 BaseClass 抽象。)

我尝试过的另一种方法是让 AnotherClass 返回一个指向对象的指针 - 但这也不适用于 object 超出范围时将被删除。

这是正确的整体方法吗?我可以从AnotherClass 返回什么,这将允许我从BaseClassfire()DerivedClass 访问getSomeDouble()

class BaseClass{
public:
    virtual void fire() = 0;
    // Use a getter and setter as you can't make a variable virtual in c++
    virtual double getSomeDouble(){ return someDouble; }
    virtual void setSomeDouble(double d){ someDouble = d; }

private:
    double someDouble;
};

class DerivedClass : public BaseClass{
public:
    void fire(){ cout << "Derived class fired. Yay." << endl; }
};


class AnotherClass{
public:
    // Set up a DerivedClass object and set someDouble to 1
    BaseClass getDerivedObject(){ // currrently fails; can't return an abstract class
        DerivedClass object;
        object.setSomeDouble(1);
        return object; // I will later want this to return vector<BaseClass> or similar
    };
};


int main()
{
    AnotherClass t;
    BaseClass o = t.getDerivedObject();
    BaseClass * p = &o;

    cout << to_string( (*p).getSomeDouble() );
    (*p).fire();
    return 0;
}

编辑:我尝试过使用这样的指针,但是当对象离开范围时,当然会被删除:

BaseClass * getDerivedObject(){
        DerivedClass object;
        object.setSomeDouble(1);
        BaseClass * p = &object;
        return p;
    };

【问题讨论】:

  • 是的,当您想使用多态性时,您必须使用指针。例如,vector&lt;BaseClass&gt; 不起作用。您可能想看看 FactoryPattern(它的方向有点不同,但与您的问题有关)
  • 基本技巧:使用std::unique_ptr&lt;BaseClass&gt;。高级技术:使用类型擦除。
  • 感谢@tobi303。我之前尝试过使用指针,但无法让它工作 - 我刚刚添加了一些我尝试的细节。
  • 是的,那是因为如果你想防止对象被破坏,你必须使用new(例如,见 Yakk 的回答)
  • 啊是的,这是有道理的。我还在考虑内存管理;)。 Yakk 和 dwcanillas,非常感谢您的回答,他们都非常有启发性 - 我会稍等片刻,以防其他人想贡献,然后选择一个答案接受。谢谢。

标签: c++ inheritance


【解决方案1】:

使用unique_ptrs 对多态对象进行伪常规访问。

template<class T>
using up=std::unique_ptr<T>;

// comes free in C++14
template<class T, class...Args>
up<T> make_unique( Args&&...args ) {
  return up<T>( new T(std::forward<Args>(args)...) );
}

up<BaseClass> getDerivedObject(){ // currrently fails; can't return an abstract class
    up<DerivedClass> object = make_unique<DerivedClass>();
    object->setSomeDouble(1);
    return object;
};

稍后:

up<BaseClass> o = t.getDerivedObject();

std::cout << to_string( o->getSomeDouble() );
o->fire();

这假设 C++11。现在是 2015 年,这似乎很安全。

使用up&lt;T&gt;make_unique&lt;T&gt;std::vector&lt; up&lt;T&gt; &gt; 意味着几乎不需要调用new。使用原始指针非常容易出错,这可以避免这种情况,同时仍然为您提供动态多态性。

【讨论】:

  • 再次感谢 Yakk 的回答。我在return object; 上遇到编译器错误; “您不能将左值绑定到右值引用”。我的 IDE 还建议我不存在从 up&lt;DerivedClass&gt;up&lt;BaseClass&gt; 的转换。你能建议解决方法吗?
  • @Giswok add std::move: return std::move(object); - 这是 C++11 中的一个缺陷,即 return-local-variable-implicitly-as-rvalue 仅在返回类型和返回的变量类型完全匹配。在 C++14 中需要支持。
猜你喜欢
  • 2015-12-15
  • 2018-07-11
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 1970-01-01
  • 1970-01-01
  • 2018-08-14
  • 1970-01-01
相关资源
最近更新 更多