Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
不能施放“;指向派生类的成员指针“;至;指向基类的成员指针“; 使用基类指针调用类的虚拟成员函数当然是C++中非常常见的事情。所以我觉得很奇怪,当你有一个成员指针而不是一个普通指针时,似乎不可能做同样的事情。请考虑以下代码: struct B { virtual void f(); }; struct D : B { virtual void f(); }; struct E { B b; D d; }; int main() { E e; // First with normal pointers: B* pb1 = &e.b; // OK B* pb2 = &e.d; // OK, B is a base of D pb1->f(); // OK, calls B::f() pb2->f(); // OK, calls D::f() // Now with member pointers: B E::* pmb1 = &E::b; // OK B E::* pmb2 = &E::d; // Error: invalid conversion from ‘D E::*’ to ‘B E::*’ (e.*pmb1).f(); // OK, calls B::f() (e.*pmb2).f(); // Why not call D::f() ??? return 0; } Visual C++继续说:_C++ - Fatal编程技术网

不能施放“;指向派生类的成员指针“;至;指向基类的成员指针“; 使用基类指针调用类的虚拟成员函数当然是C++中非常常见的事情。所以我觉得很奇怪,当你有一个成员指针而不是一个普通指针时,似乎不可能做同样的事情。请考虑以下代码: struct B { virtual void f(); }; struct D : B { virtual void f(); }; struct E { B b; D d; }; int main() { E e; // First with normal pointers: B* pb1 = &e.b; // OK B* pb2 = &e.d; // OK, B is a base of D pb1->f(); // OK, calls B::f() pb2->f(); // OK, calls D::f() // Now with member pointers: B E::* pmb1 = &E::b; // OK B E::* pmb2 = &E::d; // Error: invalid conversion from ‘D E::*’ to ‘B E::*’ (e.*pmb1).f(); // OK, calls B::f() (e.*pmb2).f(); // Why not call D::f() ??? return 0; } Visual C++继续说:

不能施放“;指向派生类的成员指针“;至;指向基类的成员指针“; 使用基类指针调用类的虚拟成员函数当然是C++中非常常见的事情。所以我觉得很奇怪,当你有一个成员指针而不是一个普通指针时,似乎不可能做同样的事情。请考虑以下代码: struct B { virtual void f(); }; struct D : B { virtual void f(); }; struct E { B b; D d; }; int main() { E e; // First with normal pointers: B* pb1 = &e.b; // OK B* pb2 = &e.d; // OK, B is a base of D pb1->f(); // OK, calls B::f() pb2->f(); // OK, calls D::f() // Now with member pointers: B E::* pmb1 = &E::b; // OK B E::* pmb2 = &E::d; // Error: invalid conversion from ‘D E::*’ to ‘B E::*’ (e.*pmb1).f(); // OK, calls B::f() (e.*pmb2).f(); // Why not call D::f() ??? return 0; } Visual C++继续说:,c++,C++,错误C2440:“正在初始化”:无法从“D E::*”转换为“B E::*” 指向的类型是不相关的;转换需要重新解释转换、C样式转换或函数样式转换 我不明白为什么这些是“不相关的”。为什么这是不可能的 编辑: 我试图保持这个C++问题,而不是我试图解决的特定问题,但这是我想做的: std::vector<B E::*> v; v.push_back( &E::b ); // OK v.push_back( &E::d ); // Error B& g( E

错误C2440:“正在初始化”:无法从“D E::*”转换为“B E::*”
指向的类型是不相关的;转换需要重新解释转换、C样式转换或函数样式转换

我不明白为什么这些是“不相关的”。为什么这是不可能的


编辑:
我试图保持这个C++问题,而不是我试图解决的特定问题,但这是我想做的:

std::vector<B E::*> v;
v.push_back( &E::b ); // OK
v.push_back( &E::d ); // Error

B& g( E& e, int i )
{
  return e.*v[i];
}

我想不出为什么这个标准不允许D e::*转换成BE::*/P>>P>简单的答案是,C++没有定义你正在尝试的转换,因此程序不正确。 考虑标准转换(C++11§4/1):

标准转换是具有内置含义的隐式转换。条例草案第4条列出所有这类转换

因为您没有执行任何强制转换,也没有定义任何自定义转换,所以您确实在执行这样的标准转换。在不列举所有可能的此类转换的情况下,有两种转换对于您的示例来说非常重要:指针转换和指针到成员转换。注意C++不考虑指针类型的指针类型是指针类型的子集。 指向成员转换的指针在C++11§4.11中定义,并由两个转换组成:

  • 空成员指针转换,允许将空指针常量转换为指向成员类型的指针(4.11/1)
  • 更为人为的第二次转换(4.11/2):

    “指向cv T类型的B的成员的指针”,其中B是类类型,可以转换为[…]“指向cv T类型的D的成员的指针”,其中D是B的派生类[…]
与前面第4.10节相比,第4.10节定义了三种指针转换:

  • 空指针转换(4.10/1),允许将空指针常量转换为指针类型
  • 转换为指向
    void
    (4.10/2)的指针,允许将任何指针类型转换为指向
    void
    的指针
  • 最后,它为什么与指针(但不是指向成员的指针)一起工作(4.10/3):

    […]指向cv D的指针(其中D是类类型)可以转换为[…]指向cv B的指针(其中B是D的基类[…])
因此,总而言之:您尝试的标准转换是为指针示例定义的,但对于指针到成员变量并不存在


C++不允许这种转换,其他许多人也喜欢这种转换,因为它会使虚拟继承的实现复杂化

struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : B, C { int d };
以下是编译器可能尝试布局这些类的方式:

A:  [ A::a ]
B:  [ B::b ] [ A ]
C:  [ C::c ] [ A ]
D:  [ D::d ] [ B ] [ C ] [ A ]
如果我们有一个指向B的指针,那么获得指向其基类a的指针不是一件容易的事情,因为它与B对象的开头没有固定的偏移量。A可能就在B::B的旁边,也可能在其他地方,这取决于我们的对象是独立的B还是作为D基础的B。我们无法知道我们有哪种情况

要进行转换,程序需要实际访问B对象并从中获取隐藏的基指针。所以真正的布局应该是这样的:

A:  [ A::a ]
B:  [ B::b | B::address-of-A ] [ A ]
C:  [ C::c | C::address-of-A ] [ A ]
D:  [ D::d | D::address-of-A ] [ B ] [ C ] [ A ]
其中,
address-of-A
s是编译器添加的隐藏成员

当我们谈论常规指针时,这一切都很好。但当我们有一个指向成员的指针时,就没有任何对象可以去获取隐藏的基指针。因此,如果我们只有
bx::*
,那么在没有实际的X对象的情况下,绝对无法将其转换为
ax::*

虽然在理论上允许这样的转换是可能的,但这将是非常复杂的。例如,指向成员的指针将需要保存可变数量的数据(指向原始对象的基值的所有隐藏指针)


理论上C++允许对成员的指针只转换到非虚拟基类(在这个例子中,代码< d x::*/c> >代码> bx::*< /> >或<代码> cx::*<代码>,但不<代码> x::*/Cord>)。或者至少我不明白为什么它会成为实现中无法克服的问题。我想这并不是因为它会给标准带来额外的复杂性,而带来的好处微乎其微。或者,标准不想排除继承的异常实现。例如,一个实现可能希望使用指向基成员的隐藏指针来实现所有继承,就好像它总是虚拟的一样(出于调试目的,或者为了与其他语言的兼容性,等等)。或者可能只是被忽略了。也许在标准(2020?)< /P>的另一个修订中,你是在询问C++设计的信息,还是标准的一部分,你不允许这样做?或者你有一个你想解决的具体问题,并且正在以一种间接的方式寻求解决方案吗?嗨@Yakk,我在标准中找不到任何东西表明这是不允许的,所以如果它在那里,如果你能给我指一下,我将不胜感激。但我也想知道为什么不允许这样做,因为这样做似乎是合理的。我想不出编译器为什么会有问题。也许我错了,但在编译器运行时,成员变量的动态类型不是总是已知的吗?真的有一个合理的场景,你会实际使用这个吗?@MikeMB,我在原来的问题中添加了一些信息。我不认为成员指针与常规指针有任何不同
A:  [ A::a ]
B:  [ B::b | B::address-of-A ] [ A ]
C:  [ C::c | C::address-of-A ] [ A ]
D:  [ D::d | D::address-of-A ] [ B ] [ C ] [ A ]