【问题标题】:Calling virtual methods of different derived classes without instantiating不实例化调用不同派生类的虚方法
【发布时间】:2018-05-14 18:14:59
【问题描述】:

我有以下类层次结构:

class Base
{
public:
    virtual void DoA();
    virtual void DoB();
    virtual void DoC();

protected:
    float m_x;
    float m_y;
};

class DerivedA : public Base
{
public:
    virtual void DoA() override;
    virtual void DoB() override;
    virtual void DoC() override;
};

class DerivedB : public Base
{
public:
    virtual void DoA() override;
    virtual void DoB() override;
    virtual void DoC() override;
};

所有方法DoA(), DoB() ...仅对基类的成员进行操作, 其中一些可能会在其中调用基类方法。在运行时,我默认创建DerivedA 类型的对象,但我可能需要将其更改为DerivedBDerivedC。但是我发现通过复制DerivedA 的状态并再次初始化它来创建这些对象是没有用的。我认为解决方案可能是将DerivedA 转换为任何其他类型,但我不确定它是否安全以及它是否是一个好的设计。有意见吗?

【问题讨论】:

  • 这是未定义的行为,您不能投射“侧面”
  • 这既不安全也不是好的设计。
  • DerivedADerivedB 有什么区别?从您的问题中听起来它们是相同的,但是没有理由存在不同的类。你能详细说明它们有何不同吗?
  • 我希望你阅读一本 C++ 初学者书籍和一些面向 OOP 设计的教程。你想实现的,这里实现的,好像不是c++可以用的方式。
  • 这看起来像是一个 XY 问题。也许您应该让我们知道您想要达到的目标。

标签: c++ casting virtual


【解决方案1】:

您给出的示例听起来像是您正在尝试开发某种状态机,其中不同的派生类是不同的状态。这通常通过使用信封/信封成语来处理,其中信封是不同的状态,而信封包含公共数据。

#include <memory>
struct letter
{
   float m_x;
   float m_y;
};
class base_envelope
{
   std::unique_ptr< letter > data_;
   base_envelope( const base_envelope & ) = delete;
   base_envelope( base_envelope && ) = delete;
public:
   base_envelope(): data_() {};
   base_envelope( std::unique_ptr< letter > & d ): data_(std::move(d)) {}
   virtual void doA() = 0;
   virtual void doB() = 0;
   void swap( base_envelope & o ) { std::swap( data_, o.data_ ); }
};
class derived1: public base_envelope
{
public:
   derived1(): base_envelope() {}

   virtual void doA() override { }
   virtual void doB() override { }
   std::unique_ptr< base_envelope > change_state();
};

class derived2: public base_envelope
{
public:
   derived2(): base_envelope() {}

   virtual void doA() override {}
   virtual void doB() override {}
   std::unique_ptr< base_envelope > change_state()
   {
     std::unique_ptr< base_envelope > r( new derived1 );
     swap( *r );
     return std::move( r );
   }
};

std::unique_ptr< base_envelope > derived1::change_state()
{
  std::unique_ptr< base_envelope > r( new derived2 );
  swap( *r );
  return std::move( r );
}

【讨论】:

    【解决方案2】:

    您最好有一个指向Base 类的指针,并在需要时创建和分配派生类的对象:

    Base * p = NULL;
    // some code ...
    p = new DerivedA;
    p->DoA(); // DoA from DerivedA class
    // some code ...
    p = new DerivedB;
    p->DoA(); // DoA from DerivedB class
    

    【讨论】:

    • 你应该避免原始的拥有指针。值得注意的是,这个例子会泄露第一个p。它们通常是一种不好的做法。在这种情况下考虑std::make_unique
    • @mezo 你是说你的派生类型存储了一个unique_ptr 给自己?还是您的意思是通过将“基础”部分作为成员来绕过继承?
    • 请使用nullptr - 我们不再做那种讨厌的NULL 宏的东西了。此外,为什么不一开始就用一些有用的东西来初始化呢?为什么还要为 null 赋值而烦恼?
    • @FrançoisAndrieux 不,我将 unique_ptr 存储到 Base 中的其他类中,我们将其称为类 Object。在 Object 类中,我想将已分配指向 DerivedA 的指针的成员 unique_ptr 转换为指向 DerivedB 的指针
    • @mezo 这真是个坏主意,DerivedA 和 DerivedA 是不同的对象
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-03
    • 2016-01-01
    相关资源
    最近更新 更多