不能向上转换指向指针参数的指针

Posted

技术标签:

【中文标题】不能向上转换指向指针参数的指针【英文标题】:Can't upcast pointer to pointer argument 【发布时间】:2017-08-27 13:00:53 【问题描述】:

我这里什么都不懂。我希望如果我可以将 dog 指针传递给采用动物指针的函数,我也可以将 &dog 传递给一个采用指向 Animal 指针的函数。

struct Animal;
struct Dog : Animal;

void ptrToPtr(Animal** arg)
void refToPtr(Animal*& arg)
void refToConstPtr(Animal* const & arg)
void ptrToConstPtr(Animal* const * arg)

int main(void)

    Dog* dog;
    Animal* animal;

    ptrToPtr(&animal); // Works
    ptrToPtr(&dog); // Argument of type Dog** is incompatible with argument of type Animal**

    refToPtr(animal); // Works
    refToPtr(dog);      // A reference of type Animal*& (not const-qualified) cannot be initialized with a value of type Dog*

    ptrToConstPtr(&animal); // Works
    ptrToConstPtr(&dog);    // Argument of type Dog** is incompatible with paramater of type Animal* const*

    refToConstPtr(animal); // Works
    refToConstPtr(dog);  // Works. This is the only one that allows me to send Dog to Animal

    return 0;

我只是不明白,任何人都可以解释为什么特定案例有效而其他案例无效的原因是什么?就像将狗指针地址传递给 Animal** 一样,那将是一种向上转换,不是吗?

【问题讨论】:

interconvertible 指针类型是指向派生/基类型对象的指针。指向指针的指针不能与其他类型相互转换。同样适用于引用。 如果你可以做ptrToPtr,你可以做*arg = new Cat;dog 将不再指向Dog 【参考方案1】:

interconvertible 指针类型是指向派生/基类型对象的指针。 “指向指针的指针”不能与其他类型相互转换void* 除外)。同样适用于引用。

这意味着给定以下任何层次结构:

struct Animal;
struct Dog : Animal;

还有以下变量:

Dog* dptr;
Animal* aptr;

dptr 可以转换为Animal*(甚至隐式),同样aptr 可以转换为Dog*(但不是隐式)。 因为:在类层次结构中向上转换始终是合法的,因此这将由 ICS 隐式完成。然而,向下转换并不总是如此,所以它从来没有隐式地完成)

但是:

Dog** ddptr;
Animal** aaptr;

ddptr 不能隐式转换为Animal**,同样aptr 不能转换为Dog**。因为,它们是两种不同的类型,没有等级关系。




上面的解释解释了为什么指向指针重载的指针会失败。 也就是说,让我们处理引用类型重载。根据您的代码,

refToPtr(animal); // Works
refToPtr(dog);      // A reference of type Animal*& (not const-qualified) cannot be initialized with a value of type Dog*

第二次调用不起作用,因为 X 的非 const 引用只能绑定到 X 的精确 glvalue 对象。由于refToPtr 采用对Animal* 类型的非常量引用,因此我们只能将Animal* 类型的glvalues 传递给它,animal 是,但dog 不是。

最后一个有效,它是合法的,因为

refToConstPtr(animal); // Works
refToConstPtr(dog);    // Works. This is the only one that allows me to send Dog to Animal

constX 的引用可以绑定到 X 的任何值类别,包括生命周期延长的临时对象。因为我们可以将dog 转换为Animal*。该转换发生并产生一个临时的Animal*,其生命周期由const 引用延长。

【讨论】:

当你说不能隐式转换时,你能强制吗?我想我可以使用 void 指针。 @Zebrafish,是的,你可以强制它。您不需要经过void* 路线。如果您绝对确定 *baseObjectPtr 最初属于 Derived 类型,则可以使用 static_cast<Derived*>(baseObjectPtr)。或者dynamic_cast<Derived*>(baseObjectPtr),如果你不能确定... 但是没有,这不适用于你的问题。因为Animal**Dog**没有关系

以上是关于不能向上转换指向指针参数的指针的主要内容,如果未能解决你的问题,请参考以下文章

在方法中返回向上转换的指针时替代堆分配

什么时候在 C++ 中向上转型是非法的?

指向整数转换的不兼容指针将“SystemSoundID”传递给“SystemSoundID”类型的参数

指向整数转换的不兼容指针将“void *”发送到“PHImageContentMode”类型的参数(又名“枚举 PHImageContentMode”)

向上转换函数指针是不是安全?

调用旧版 C API 时,如何在现代 C++ 中正确地将指向结构的指针转换为指向其他结构的指针?