2012-04-04 103 views
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标准允许它,但需要设置一个特殊的编译参数?

+0

我想我很理解为什么编译器报告类型不匹配。我需要的不是对这里发生的事情的解释。我需要一些开箱即用的东西。为了进一步解释它,请参阅添加的额外说明。 – 2012-04-04 13:41:38

回答

2

简单的答案是“否”。

你已经失去的额外信息(child*而不是father*)约ref当你扔掉m_child S型的信息,将它存储为指针基地(pf)。

一个原因就是它永远无铸有可能是这样的例子:

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>(); 
+0

谢谢,你给我提供了一些看起来更好的东西! – 2012-04-04 13:54:35

1

您的功能可以满足您的期望以及您的要求。该行

child* pc = pf->ref(); 

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

child *pc = m_child.ref(); 
father *pf = m_child.ref(); 
father *pf2 = pf->ref(); 
+0

很好解释@dascandy – Ricketyship 2012-04-04 13:28:00

1

的问题是,在呼叫pf->ref()ref类型是:father* (father::*)()

也就是说,ref被解析为静态地是具有给定签名的virtual方法。这个签名表示它返回一个father*

这样:

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

    child c; 
    child* pc = &c; 

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

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