【问题标题】:cast base class pointer to one of several possible derived type pointer based on condition根据条件将基类指针转换为几种可能的派生类型指针之一
【发布时间】:2012-02-02 22:45:15
【问题描述】:

我有一个基类B 和几个派生模板类D<int>D<float>D<double> 等(这么多)

在我的程序中,我发现有一个 B 指针,我知道该指针指向 D 特化之一的实例。我还有一个标识派生类型的唯一键。

所以,我想使用我的基类指针和唯一类型键调用正确的派生类方法。我实际上想在几个地方这样做,所以我想出的一个解决方案不仅丑陋,而且很麻烦。

在 C++ 中有没有更好的方法来访问具有基指针和唯一键的派生类成员?

我不想/不能修改基类。 boost库是公平的游戏。

这是我的潜在代码,但我不喜欢在需要访问派生成员函数/变量的任何地方复制它。所有这一切都是为了一个成员函数调用?!!

B * bptr = ...
std::type_info * typekey = ...

if        (typekey == &typeid(D<float>) ) {
    D<float> * dptr = static_cast<D<float>*>(bptr);
    dptr->derivedMember();
} else if (typekey == &typeid(D<double>) ) {
    D<float> * dptr = static_cast<D<double>*>(bptr);
    dptr->derivedMember();
} else if (typekey == &typeid(D<int>) ) {
    D<float> * dptr = static_cast<D<int>*>(bptr);
    dptr->derivedMember();
} 

【问题讨论】:

  • 为什么不让derivedMember() 成为一个虚函数?
  • +1 到@KerrekSB,同样如果 derivedMember 是 D 的成员函数(但不是 B),您可以在 D 和 B 之间引入一个基类 C,将 derivedMember 作为虚函数添加。
  • @KerrekSB 我看不出在这种情况下将派生成员设为虚拟会有什么帮助。它们不存在于基类中。我看到引入中间类可能是一种选择。考虑到现有的阶级关系,我想我真的希望有一些可行的方法,但我当然不会坚持下去。

标签: c++ casting rtti derived-types


【解决方案1】:

如果所有D&lt;type&gt;:: 方法都具有相同的名称“DerivedMember”,并且我假设基类 B 没有将其声明为虚拟,您能否更改您的层次结构:

class B { etc. };

template<class T>
class D : public B
{
};

到:

class B { etc. };

class C : public B
{
 virtual void derivedMember() = 0;
};


template<class T>
class D : public C
{
public:
void derivedMember() { etc. };
};

那么你可以:

void f(C* c) /* or take a B* and do: C* c = static_cast<C*>(b); */
{    
  c->derivedMember();
}

【讨论】:

  • 我正在探索在我的代码中创建一个中间类的想法。 @Keith 你可能是指中产阶级是class C : public B 对吧?至少,我不知道您可以将模板类声明为同名的非模板类。也许你可以...
  • 我最喜欢你的解决方案,但发现它有点不完整,所以我编辑了。
  • 谢谢。当然,无论如何为中间体使用不同的名称会更清晰。请注意,我认为这实际上是对“薄模板”模式的一种理解——通常为模板提供一个基类,其中包含不需要模板化的所有内容。
【解决方案2】:

如 cmets 中所述,处理这种情况的正确方法是引入 virtual 方法并让 C++ 正确调度调用。

由于您不能修改基类,您可以插入一个具有虚函数的新类,并从新类派生所有类。

如果您需要使用许多功能(可能尚未定义且客户端代码将提供的功能)复制此行为,您可以利用Visitor pattern。事实上,如果您无法更改基类,您至少可以使用类似 Vistior 的技术将繁琐的 typekey 检查保持在一个位置,并将实际操作取出到单独的类中。如果另一个 derivedMember 类似函数,这将使您不必重写 typekey 检查。

【讨论】:

    【解决方案3】:

    我认为使用 dynamic_cast 可以解决问题:

        B* base
        if(Class1* c1 = dynamic_cast<Class1*>(base))
        // it's a Class1*
        else if (Class2* c2 = dynamic_cast<Class2*>(base))
        // it's a Class2*
    

    【讨论】:

      猜你喜欢
      • 2013-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-10
      • 2011-02-01
      • 2016-12-31
      • 1970-01-01
      相关资源
      最近更新 更多