具有私有基数的函数成员指针
以下代码会产生编译时错误:
'
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
}
The following code yields a compile time error:
'
base::print
' : cannot access private member declared in class 'base_der
'
However, I have made the member public
in the derived class. Why doesn't this work?
#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
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为有一些相互作用的问题导致了该错误:
base_der::print< /code> 是可访问的,但类
base
仍然不可访问,并且在尝试转换指向成员的指针时,指向成员类型的指针中的类的实际类型是的考虑。C++03 7.3.3“using 声明”
请注意,虽然该名称被引入新的“区域”,但它是一个同义词 - 该名称所指的类型是相同的。因此,我认为在您的示例中,名称
base_der::print
的类型为void (base::*)(int)
,而不是类型void ( base_der::*)(int)
。C++03 标准还对指针到成员类型之间的转换进行了规定(4.11“指向成员转换的指针”):
另请注意 7.3.3/13“using 声明”(添加了强调):
现在,生成错误的代码示例:
正在尝试转换“指针” D 的成员”到“B 的成员的指针”——这是错误方向的转换。如果您想一下,您就会意识到为什么朝这个方向进行转换并不安全。 “指向 B 成员的指针”类型的变量可能不会与与 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++ 中的某些东西是更复杂或不太容易理解的领域之一时,这已经说明了很多。
I think there are a few interacting problems contributing to the error:
base_der::print
is accessible, the classbase
still isn't and in an attempt to convert a pointer-to-member, the actual type of the class in the pointer-to-member type is part of the consideration.C++03 7.3.3 "The using declaration"
Note that while the name is brought into the new 'region', it's a synonym - the type of what the name refers to is the same. So, I think that in your example, the name
base_der::print
has a typevoid (base::*)(int)
, not typevoid (base_der::*)(int)
.The C++03 standard also says this about conversions between pointer-to-member types (4.11 "Pointer to member conversions"):
Also note 7.3.3/13 "The using declaration" (emphasis added):
Now, the code example that generates an error:
is trying to convert a "pointer to member of D" to a "pointer to member of B" - which is a conversion in the wrong direction. If you think about it for a moment, you'll realize why a conversion in this direction isn't safe. A variable of type "pointer to member of B" might not be used with an object that has anything to do with
class D
- but if you call a function with type "pointer to member of D" (which is whatvoid (base_der::* print)(int)
is), it'll rightly expect that thethis
pointer will be pointing to aD
object.Anyway, while I think that the root of the problem is this conversion problem, I think you're getting a complaint about the accessibility because when the compiler is trying to handle the conversion, it's first checking the accessibility of
base
- and even though the namebase_der::print
(which is an alias forbase::print
) is accessible because of theusing
declaration, classbase
still isn't.Disclaimer: this analysis is coming from someone who has little experience in the nuances of pointer-to-member types. They're an area of C++ that is complex, difficult to use except in the simplest scenarios, and apparently have a lot of portability problems (see Doug Clugston's article, http://www.codeproject.com/KB/cpp/FastDelegate.aspx, which is old enough that a lot of these problems may have been addressed by now, but I suspect they aren't).
And when you say that something in C++ is one of the more complex or less-well-understood areas, that's saying a lot.
我不能说我知道为什么(我也不能谈论规范),但 clang 的错误消息可能具有启发性:
因此,更改成员函数的类型至少在 clang 和 gcc 中有效:
I can't say I know why (nor can I speak to the spec), but clang's error message may be instructive:
So changing the type of the member function works, in clang and gcc at least:
这是因为,
继承是
私有的
。因此base_der
无法访问base
。将其更改为public
就可以了。It's because,
Inheritance is
private
. Sobase
is inaccessible tobase_der
. Change that topublic
and it will work.