Ser*_*upu 5 c++ member-function-pointers member-pointers implicit-conversion private-inheritance
以下代码产生编译时错误:
'
base::print':无法访问类中声明的私有成员'base_der'
但是,我已public在派生类中创建了该成员.为什么这不起作用?
#include <iostream>
using namespace std;
class base
{
public:
int i;
void print(int i)
{
printf("base i\n");
}
};
class base_der : private base
{
public:
using base::print;
};
int main()
{
// This works:
base_der cls;
cls.print(10);
// This doesn't:
void (base_der::* print)(int);
print = &base_der::print; // Compile error here
}
Run Code Online (Sandbox Code Playgroud)
我认为有一些相互作用的问题导致错误:
base_der::print是可访问的,但类base仍然不是并且在尝试将指针转换为成员时,指向成员类型的类的实际类型是考虑的一部分.C++ 03 7.3.3"使用声明"
using声明在声明区域中引入了一个名称,其中出现using声明.该名称是其他地方声明的某个实体名称的同义词.
请注意,虽然名称被带入新的"区域",但它是同义词 - 名称所指的类型是相同的.所以,我认为在你的例子中,名称base_der::print有一个类型void (base::*)(int),而不是类型void (base_der::*)(int).
C++ 03标准还说明了指针到成员类型之间的转换(4.11"指向成员转换的指针"):
类型为"cv T类型的B成员的指针"的右值,其中B是类类型,可以转换为类型为"指向类型为cv T的D的成员的指针"的右值,其中D是派生类(如果B是不可访问的(第11条),D的模糊(10.2)或虚拟(10.1)基类,则需要这种转换的程序是不正确的.转换的结果引用与转换发生前指向成员的指针相同的成员,但它引用基类成员,就好像它是派生类的成员一样.结果引用D的B实例中的成员.由于结果具有类型"指向cv T类型的D的成员的指针",因此可以用D对象取消引用它.结果与指向B成员的指针与D的B子对象取消引用的结果相同.
另请注意7.3.3/13"使用声明"(重点补充):
出于重载解析的目的,将using声明引入派生类的函数将被视为它们是派生类的成员.特别是,隐式this参数应被视为指向派生类而不是基类的指针.这对函数的类型没有影响,并且在所有其他方面,函数仍然是基类的成员.
现在,生成错误的代码示例:
// This doesn't:
void (base_der::* print)(int);
print = &base_der::print; // Compile error here
Run Code Online (Sandbox Code Playgroud)
试图将"指向D成员的指针"转换为"指向B成员的指针" - 这是一个错误方向的转换.如果你想一下,你就会明白为什么这个方向的转换不安全."指向B成员的指针"类型的变量可能不会与有任何关联的对象一起使用class D- 但是如果调用类型为"指向D成员的指针"的函数(它是什么void (base_der::* print)(int)),它将会正确地期望this指针指向一个D对象.
无论如何,虽然我认为问题的根源是这个转换问题,但我认为你得到了关于可访问性的抱怨,因为当编译器试图处理转换时,它首先检查可访问性base- 即使名称base_der::print(这是别名base::print)是可以访问的,因为using声明,类base仍然不是.
免责声明:此分析来自于对指针到成员类型的细微差别几乎没有经验的人.它们是C++的一个复杂领域,除了最简单的场景外很难使用,并且显然存在许多可移植性问题(参见Doug Clugston的文章,http://www.codeproject.com/KB/cpp/FastDelegate. aspx,已经足够老了,现在可能已经解决了很多这些问题,但我怀疑它们不是).
当你说C++中的某些东西是更复杂或更不易理解的领域之一时,那就说了很多.
这是因为,
class base_der : private base
Run Code Online (Sandbox Code Playgroud)
继承是private。所以base是无法访问的base_der。将其更改为public,它将起作用。
| 归档时间: |
|
| 查看次数: |
509 次 |
| 最近记录: |