0

这个问题是关于用不同的返回类型覆盖派生类中的虚拟方法。对于以下代码:

class father {
public:
  virtual father* ref() { return this; }
};

class child : public father {
  virtual child* ref() { return this; }
};

当我尝试直接获取指针时,g++ (F15, g++4.5) 报告“从父亲到孩子的无效转换”

child m_child;
father* pf = &m_child;
child* pc = pf->ref();

我了解使用了子类中的 ref() 方法,这可能只是编译时类型不匹配。

但是,有没有办法在不显式使用类型转换的情况下做到这一点?

额外说明:我理解编译器报这个错误的原因。我需要的是开箱即​​用的东西,它可以访问派生对象中的数据,而无需显式转换指针。

父类用于将不同的派生子对象放入列表或向量中,因此当从列表或向量中获取项目时,无法分辨它属于哪个子类。

我有内部方法来记录和检查子类类型。但我不想显式转换指针。

例如,我想做这样的事情:

// assuming pf is pointer pointed to an item fetch from a vector
switch(fp->get_type()) {
case child_type1: fp->ref()->list1.push(data); break;
case child_type2: fp->ref()->list2.push(data); break;
case child_type3: fp->ref()->list3.push(data); break;
}

现在,我需要在每种情况下以及每次需要访问派生类中的数据时显式声明一个新变量或显式将 fp 转换为正确的类型,这既乏味又令人困惑。

我期望的是:可能是一些 boost 库可以以我还不知道的另一种方式做类似的事情,或者可能是 c++11 标准允许它但需要设置一个特殊的编译参数?

4

3 回答 3

2

简单的答案是“不”。

通过将 s 类型信息存储为指向基 ( ) 的指针,您丢失了有关 何时丢弃s 类型信息的额外信息 (child*而不是)。father*refm_childpf

没有演员表就永远不可能的一个原因是这个例子:

class father {
public:
  virtual father* ref() { return this; }
};

class childA : public father {
  virtual childA* ref() { return this; }
};

class childB : public father {
  virtual childB* ref() { return this; }
};

void should_never_compile(int i)
{
   childA a;
   childB b;
   father pf;
   if( i ) { pf=&a; }
   else { pf=&b; }

   // This is evil and will not compile
   childA * pa = pf->ref();

   //But this is OK:
   childA * pa = dynamic_cast<childA*>(pf->ref() );
}

如果你真的想在没有动态演员表的情况下做到这一点,你可以隐藏动态演员表(但这让我有点害怕)

class father {
public:
  virtual father* ref() { return this; }
  template<typename T> T* as() { return dynamic_cast<T*>(ref()); }
};

child m_child;
father* pf = &m_child;
child* pc = pf->as<child>();
于 2012-04-04T13:41:03.227 回答
1

你的函数做你所期望的和你告诉它的。线

child* pc = pf->ref();

是问题所在。您在指向父亲的指针上调用函数“ref()”,它返回(按类型)父亲 *。您将其分配给子 *. 该函数的实现返回一个子 *,但是从你调用它的地方,你不知道该信息,因为你只知道它是一个父亲 *。因此,返回类型是一个父亲 *(如父类中所示),并且您将其分配给子 * 而不转换。你可以这样做:

child *pc = m_child.ref();
father *pf = m_child.ref();
father *pf2 = pf->ref();
于 2012-04-04T13:25:03.903 回答
1

问题是在 callpf->ref()中,类型ref是:father* (father::*)()

也就是说,静态ref解析为具有给定签名的方法。这个签名表明它返回一个.virtualfather*

因此:

int main() {
  father f;
  father* pf = &f;

  child c;
  child* pc = &c;

  child* xf = pf->ref(); // compile-time failure
  child* xc = pc->ref(); // okay
}

问题是,一般来说,从 a 开始father*你不知道你是否会得到 a child*,这取决于实例的动态类型。所以编译器假设最坏的情况:它必须至少是father.

于 2012-04-04T13:26:23.123 回答