引用指针和 C++ 多态性

Posted

技术标签:

【中文标题】引用指针和 C++ 多态性【英文标题】:Reference to pointers and C++ polymorphism 【发布时间】:2009-05-22 17:17:30 【问题描述】:

有谁知道为什么这会导致编译器错误?我试过 VS 2005 和 Codewarrior:

class Parent 
   protected:
      int m_Var;
   public:
      Parent() : m_Var(0) 
      virtual ~Parent() 
      void PubFunc();
;

class Child : public Parent 
   protected:
      bool m_Bool;
   public:
      Child() : m_Bool(false) 
      virtual ~Child() 
      void ChildFunc();
;

void RemoveObj(Parent *& ppObj)

   delete ppObj;
   ppObj = 0;


int main()

   Parent* pPObj = 0;
   Child*  pCObj = 0;
   pPObj = new Parent();
   pCObj = new Child();

   RemoveObj(pPObj);
   RemoveObj(pCObj);
   return 1;

视觉工作室说:

refptr.cpp(33):错误 C2664: “RemoveObj”:无法转换参数 1 从“子 *”到“父 *&”

谢谢

【问题讨论】:

【参考方案1】:

RemoveObj 的 ppObj 参数是对 Parent* 的引用。如果RemoveObj() 方法将指针替换为指向新Parent 对象的指针怎么办?当方法返回您的 pCObj Child* 将不再指向 Child 对象。

【讨论】:

【参考方案2】:

来自 C++ 标准 (1998)

除非在上下文中 用户自定义初始化 转换 (13.3.1.4, 13.3.1.5), a 格式良好的隐式转换 序列是以下之一 形式:——标准转换 序列(13.3.3.1.1),-用户 定义...

13.3.3.1.1

每个转化最多一次 类别允许在单个 标准转换顺序

所以 c++ 不能连续两次隐式转换:从指针到指针,然后再从指针。

为了解决这个问题,考虑这样的 RemoveObj 声明

void RemoveObj(Parent ** ppObj)

你会看到这个错误

error: invalid conversion from 'Child**' to 'Parent**'

你必须像这样使用显式转换

   RemoveObj((Parent**)&pCObj);
   RemoveObj((Parent*&)&pCObj);

或者不得不改变

void RemoveObj(Parent *& ppObj)

void RemoveObj(Parent * ppObj)

或到

template <typename T>
void RemoveObj(T *& pObj)

   delete pObj;
   pObj = 0;

【讨论】:

这并不能回答为什么它是编译器错误,但它应该被更改为。对指针的引用对于执行该方法正在执行的操作不是必需的。 我已经添加了对标准的引用。 通过编辑,这绝对是您为什么会遇到编译器错误的答案。根据@MykolaGolubyev 指出的标准部分,您正在尝试进行两步转换,这是非法的。不幸的是,reinterpret_cast 是解决这个问题的最实用的方法。【参考方案3】:

ppobj 是指针的引用。 *ppobj 取消引用变量指向的内容,因此您可以获取变量指针。

由于取消引用的类型不正确,您会看到错误。

【讨论】:

【参考方案4】:

指向引用的指针允许指针值在函数中改变。正如Michael Burr 所指出的,可能会分配不正确的类引用并返回它。想象一下你的整个程序错误地使用 *pchickens 作为 *peggs :)

我认为值得添加(尽管没有明确您的要求): 我对多态实现的偏好是将常用函数作为方法移动到内部。如果它们都共享一个函数,只需将其添加到基类中即可。

那么无论哪种方式,您都可以简单地调用 Foo->Bar() 并达到预期的效果。但是对于您给出的具体实现示例,只需 delete Foo 将调用适当的析构函数。

【讨论】:

【参考方案5】:

这不是权威,但我认为问题在于 C++ 类的多态性并没有扩展到它们的指针;您期望在这里完成的是将Child * 转换为Parent *;虽然您可以将 Child 转换为 Parent,但您不能将指针 reference 转换。也就是说,类是多态的,但指向类的指针在作为引用时不是。这是迈克尔·伯尔(Michael Burr)在上面给出的原因; Child * 暗示了某种Parent * 没有的内存结构。

【讨论】:

指针之间的转换是可能的。但是,转换会临时返回一个右值。这就是它不能传递给非常量引用的原因。 问题出在参考,而不是指针。您可以互换地传递指针,但不能传递对不同类型指针的引用。 我认为您在谈论将左值转换为左值 w.r.t Child* 到 Parent*。你是对的,这样的转换是不可能的。但是您的帖子听起来像是在暗示 Child* to Parent* 是不允许的(事实并非如此)。没有投反对票,只是帮助你弄清楚他们为什么会反对你。 (如果他们只告诉你......) @litb:感谢您对解释的澄清;编辑使其更清晰。 可以做这个实验:void f(Parent * const& p);你可以用 f(pChild) 来调用它;因为隐式指针转换为 Parent* 的结果可以绑定到参数 p:它是一个非常量引用。由于我们不是在此处操作“多态”(我们不是说“参数 Child* 指针是参数 Parent* 指针”)而是在副本上操作,因此可以正常工作。我相信这就是你的意思。

以上是关于引用指针和 C++ 多态性的主要内容,如果未能解决你的问题,请参考以下文章

c++实现多态一定要用指针吗

解密C++多态属性

C++继承多态总结

C++多态 --- 多态实现原理简析

C++ 类指针

4.虚函数-多态