【问题标题】:How conversion of pointer-to-base to void is better than pointer-to-derived to void conversion从指针到基地址到 void 的转换如何优于从派生指针到 void 的转换
【发布时间】:2022-07-06 23:12:17
【问题描述】:

[over.ics.rank]/4:

  • [..]
  • (4.3) 如果 B 类直接或间接从 A 类派生,则 B* 到 A* 的转换优于 B* 到 void* 的转换,A* 到 void* 的转换优于 B 的转换* 作废*。

如果我有:

struct A {};
struct M : A {};
struct B : M {};

void f(A*);
void f(void*);

int main()
{
   B *bptr = new B();
   f(bptr);
}

调用f(bptr) 更喜欢重载f(A*) 而不是f(void*)

但在第二种情况下:将 A* 转换为 void* 优于将 B* 转换为 void*。这种转换是如何发生的?你能给我一个触发这个案例的例子吗?


由于某些原因,我找不到适用此案例的案例或示例。似乎将两个不相关的事物相互比较。但我在子弹4.4遇到更多。

你可以从cppreference第4段检查整个事情:

  1. 如果 Mid 是(直接或间接)从 Base 派生的,并且 Derived 从 Mid 派生(直接或间接)
  • a) Derived* to Mid* 优于 Derived* to Base*
  • b) 派生到 Mid& 或 Mid&& 优于 Derived to Base& 或 Base&&
  • c) Base::* to Mid::* 优于 Base::* to Derived::*
  • d) Derived to Mid 优于 Derived to Base
  • e) Mid* to Base* 优于 Derived* to Base*
  • f) Mid to Base& 或 Base&& 优于 Derived to Base& 或 Base&&
  • g) Mid::* 到 Derived::* 优于 Base::* 到 Derived::*
  • h) Mid to Base 优于 Derived to Base

我要问的是从e)点开始

所以如果MidMBaseBDerivedD,我有以下类:

struct B { int mem{}; };
struct iM : B {};
struct M : iM {}; // M is derived indirectly from B
struct jM : M {};
struct D : jM {}; // D is derived indirectly from M and from B.

从 e 点:M* 到 B* 优于 D* 到 B*。这怎么会发生?

【问题讨论】:

  • 也许如果你只有void* 过载,它会去B* -> A* -> void*?这对于 B*A* 指向不同位置的深层继承可能很重要。
  • 或多个参数:void f(A*, void*); void f(void*, B*); A *aptr = new A(); f(aptr, bptr); 会选择 f(void*, B*)?
  • void* 那是什么?开个玩笑,只是好奇,C++ 中的 void* 有什么用? (除非它是为了与一些遗留 api 通信)。还是有一点语言的修饰?
  • @GoswinvonBrederlow 根据标准的重载解析从不考虑不同位置的参数之间的序列排名。这通常会使似乎具有明显更可取的重载的调用变得模棱两可,这就是为什么一些编译器为这些情况实现了一些合理的解决方案,但它们不符合标准。

标签: c++ class overload-resolution


【解决方案1】:

您必须比较不同的可能源类型(A* -> void*B* -> void* 中的A*B*)的情况只能发生在通过用户定义的转换进行初始化的重载解析上下文中,而不是在函数调用的重载决议的上下文。另请参阅note at the end of [over.ics.rank]/4

以下是引用短语相关的示例:

struct A {};
struct B : A {};

struct C {
    operator A*();
    operator B*();
};

int main() {
    void* x = C{};
}

这里x 由根据[over.match.conv] 选择的转换函数初始化(请参阅[dcl.init.general]/16.7。所有从C 转换为可通过标准转换序列转换为void* 的类型的转换运算符都被考虑.

然后根据转换函数后面的标准转换序列中哪个更好(参见[over.match.best.general]/2.2)来选择最佳转换函数。

你引用的那句话告诉我们A* -> void*B* -> void* 更好。所以这里用来初始化x的转换函数是operator A*()

【讨论】:

    猜你喜欢
    • 2020-05-06
    • 2016-01-20
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    相关资源
    最近更新 更多