繁体   English   中英

从Derived *转换为Base *&

[英]Converting from Derived* to Base*&

我试图通过将引用传递给指针而不是指向指针的指针来回答这里提到的问题,如下所示:

class Parent 
{
};

class Child : public Parent 
{
};

void RemoveObj(Parent*& pObj)
{
    delete pObj;
    pObj = NULL;
}

int main()
{
    Parent* pPObj = new Parent;
    Child*  pCObj = new Child;
    pPObj = new Parent();
    pCObj = new Child();



    RemoveObj(pPObj);
    RemoveObj(pCObj); // This is line 32
    return 1;
}

但是这会在第32行产生以下编译器错误:

错误C2664:'RemoveObj':无法将参数1从'Child *'转换为'Parent *&'

我同意不允许从Child **转换为Parent **。 但为什么这种转换也不允许?

Child*类型的对象不能绑定到Parent*&原因与Child**无法转换为Parent**原因完全相同。 允许它允许程序员(有意或无意)在没有演员表的情况下打破类型安全。

class Animal {};

class DangerousShark : public Animal {};

class CuteKitten : public Animal {};

void f(Animal*& animalPtrRef, Animal* anotherAnimalPtr)
{
    animalPtrRef = anotherAnimalPtr;
}

void g()
{
    DangerousShark myPet;
    CuteKitten* harmlessPetPtr;

    f(harmlessPetPtr, &myPet); // Fortunately, an illegal function call.
}

编辑

我认为由于“转换”和“转换”这两个词的使用松散,引起了一些混乱。

与可以重新分配的对象不同,引用不能被反弹,因此在我们提到转换的引用的上下文中,我们只关心初始化新引用。

引用总是绑定到一个对象,并且从OP的问题很明显,他的目标是获得一个直接绑定到现有对象的引用。 仅当用于初始化引用的对象与引用类型引用兼容时 ,才允许这样做。 本质上,这只是在类型相同的情况下,或者对象的类型是从引用的类型派生的,并且引用类型至少与初始化对象一样是cv限定的。 特别是,无论指向类型的关系如何,指向不同类型的指针都不是引用兼容的。

在其他情况下,可以使用可以转换为引用类型的内容来初始化引用。 但是,在这些情况下,引用必须是const而不是volatile,转换将创建一个临时引用,并且引用将绑定到此临时对象而不是原始对象。 正如所指出的,这不适合OP的激励示例的要求。

总之, Child可以直接绑定到Parent&但是Child*不能直接绑定到Parent*& 可以使用Child*初始化Parent* const& ,但引用实际上将绑定到从Child*对象复制初始化的临时Parent* Child*对象。

  • 您的类没有虚函数。 FAQ 20.7

  • Beacuse Parent *&是对Parent对象的指针的引用。 您正在传递指向Child的指针 - 这些是不兼容的类型。 您可以将临时绑定到const-reference,即如果将参数更改为:

    void RemoveObj(Parent* const& foo);

但是,你将无法做到这一点。

它只是一个测试代码,所以我没有做任何虚拟析构函数。 如果我在第二次调用RemoveObj()时理解正确,我会得到一个临时的Parent *对象,它可以作为const引用传递给函数。 这个对吗?

我强烈建议您在标准C ++ 98模式下运行以下程序,一次运行,然后在注释掉foo(b)和取消注释delete b之后再运行一次。 接下来,尝试在~s()之前放入virtual 差异应该是不言自明的!

#include <iostream>
using namespace std;
struct s { 
  s() {cout << __func__ << endl; }
  ~s() {cout << __func__ << endl; } 
};

struct t : s { 
   t() {cout << __func__ << endl; }
   ~t() {cout << __func__ << endl; } 
};

void foo(s* const& x) { delete x; }

int main() {
 t* b = new t;
 foo(b);
 //delete b;
}

您可以将Child* to a Parent*转换为Child* to a Parent* :这会创建一个临时的。 但是你不能将非const引用绑定到那个临时的。

这不是**/*&/etc 你要做的是完全没问题,也是有道理的。 Shark vs. Kitten也有同样的问题:不是混合小猫和鲨鱼的问题。 您不能将非const引用绑定到该未命名的指针。

这不是Parent** vs. Child**问题:如果Child**Parent** ,那么可以指定p[0] = new NotAChild; A的所有子类型的对象集合不是A的集合。

type *&是**类型的另一种语法形式,Parent *&和Child *&彼此无关以及Parent **和Child ** - 这些是不在一个类层次结构中的不同类型。

由于Dirk提到的原因,这不起作用。 如果你真的需要一个RemoveObj方法,那么我只是将你新分配的Child对象保存为Parent *:

#include <iostream>

class Parent 
{
public:
    virtual ~Parent()
    {
        std::cout << "Parent destructor" << std::endl;
    }
};

class Child : public Parent 
{
public:
    virtual ~Child() 
    {
        std::cout << "Child destructor" << std::endl;
    }
};

void RemoveObj(Parent*& pObj)
{
    delete pObj;
    pObj = NULL;
}



int main (int argc, const char * argv[]) {

    Parent* pPObj = new Parent;
    Parent*  pCObj = new Child;

    RemoveObj(pPObj);    
    RemoveObj(pCObj); // This is line 32


    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM