C++ 具有私有基的函数成员指针
以下代码产生编译时错误: “C++ 具有私有基的函数成员指针,c++,implicit-conversion,member-function-pointers,member-pointers,private-inheritance,C++,Implicit Conversion,Member Function Pointers,Member Pointers,Private Inheritance,以下代码产生编译时错误: “base::print”:无法访问类“base\u der”中声明的私有成员 但是,我已经在派生类中公开了成员。为什么这样不行 #include <iostream> using namespace std; class base { public: int i; void print(int i) { printf("base i\n"); } }; class base_der : private
base::print
”:无法访问类“base\u der
”中声明的私有成员
但是,我已经在派生类中公开了成员。为什么这样不行
#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
}
#包括
使用名称空间std;
阶级基础
{
公众:
int i;
作废打印(int i)
{
printf(“基本i\n”);
}
};
类基\u顺序:私有基
{
公众:
使用base::print;
};
int main()
{
//这项工作:
基础设施;
cls印刷品(10);
//这并不是:
无效(基本顺序::*打印)(整数);
print=&base\u der::print;//此处编译错误
}
因为
class base_der : private base
继承是私有的。因此base
对base\u der
是不可访问的。将其更改为public
,它将起作用。我不能说我知道原因(我也不能对规范说话),但clang的错误消息可能有指导意义:
error: cannot cast private base class 'base' to 'base_der'
因此,更改成员函数的类型至少在clang和gcc中有效:
void (base::* print)(int);
print = &base_der::print; // works!
我认为有几个相互作用的问题导致了这个错误:
指向成员类型的指针具有非直观的类型转换特性
using声明不影响引入范围的名称的类型
虽然名称base\u der::print
是可访问的,但类base
仍然是不可访问的,并且在尝试转换指向成员的指针时,指向成员类型的指针中的类的实际类型是考虑的一部分
C++03 7.3.3“使用声明”
using声明在using声明出现的声明性区域中引入名称。该名称是在别处声明的某个实体名称的同义词
请注意,当名称被引入新的“区域”时,它是一个同义词——名称所指的类型是相同的。因此,我认为在您的示例中,名称base\u der::print
有一个类型void(base:*)(int)
,而不是类型void(base\u der:*)(int)
C++03标准还规定了指针到成员类型之间的转换(4.11“指针到成员转换”):
“指向cv T类型B的成员的指针”类型的右值(其中B是类类型)可以转换为“指向cv T类型D的成员的指针”类型的右值,其中D是B的派生类(第10条)。如果B是D的不可访问(第11条)、不明确(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
正在尝试将“指向D的成员的指针”转换为“指向B的成员的指针”-这是错误方向的转换。如果你想一想,你就会明白为什么向这个方向转换是不安全的。类型为“指向B的成员的指针”的变量可能不用于与类D
有关的对象,但是如果调用类型为“指向D的成员的指针”的函数(这就是void(base_der::*print)(int)
的含义),它正确地期望这个指针将指向D
对象
无论如何,虽然我认为问题的根源是这个转换问题,但我认为您正在收到关于可访问性的投诉,因为当编译器试图处理转换时,它首先检查base
-的可访问性,即使名称base\u der::print
(它是base::print
的别名)是可访问的,因为使用声明,类base
仍然不可用
免责声明:这种分析来自于对成员类型指针的细微差别缺乏经验的人。它们是C++的一个复杂的领域,除了最简单的情况下难以使用,而且显然有很多可移植性问题。(参见道格·克拉格斯顿(Doug Clugston)的文章,这篇文章已经足够老了,到目前为止,这些问题可能已经得到了解决,但我怀疑它们还没有得到解决)
<>和当你说C++中的某个东西是更复杂或不太好理解的区域时,那是说了很多。你有<代码>类基数:私下的基础< /代码>。@ SyBLUPU你的例子已经足够清楚地迷惑我们了。我现在终于明白你的问题了,我无法解释它。我已经修改了这个问题。(希望)说得更清楚。我还纠正了一个错误:您在派生类中编写了base::print;
,但需要使用base::print编写,
!@KonradRudolph“您在派生类中编写了base::print;
,但需要使用base::print编写!”这是历史语法,在使用
关键字之前。@0A0D是的,但问题是为什么这是个问题。它不应该是个问题。不。我错了。我授予函数的公共访问权限