具有私有基础的函数成员指针 [英] Function member pointer with private base

本文介绍了具有私有基础的函数成员指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码产生编译时错误:

The following code yields a compile time error:

'base::print':无法访问类'base_der'

'base::print' : cannot access private member declared in class 'base_der'

但是,我已经在派生类中使成员public.为什么这行不通?

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
}

推荐答案

我认为有一些相互作用的问题导致了该错误:

I think there are a few interacting problems contributing to the error:

  1. 指针到成员类型具有不直观的类型转换特征
  2. using声明不会影响引入作用域的名称的类型
  3. 虽然名称base_der::print是可访问的,但类base仍然不可用,并且在尝试转换指针成员时,指针成员类型中类的实际类型是其中的一部分的考虑.
  1. pointer-to-member types have unintuitive type conversion characteristics
  2. the using declaration doesn't affect the type of the name brought into scope
  3. while the name base_der::print is accessible, the class base 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正在使用的声明"

使用声明将名称引入使用声明的显示区域.该名称是在其他地方声明的某些实体名称的同义词.

A using-declaration introduces a name into the declarative region in which the using-declaration appears. That name is a synonym for the name of some entity declared elsewhere.

请注意,虽然将名称带入新的区域",但它是同义词-名称所指的类型相同.因此,我认为在您的示例中,名称base_der::print具有类型void (base::*)(int),而不是类型void (base_der::*)(int).

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 type void (base::*)(int), not type void (base_der::*)(int).

C ++ 03标准还说了有关指针到成员类型之间的转换( 4.11指针到成员转换" ):

The C++03 standard also says this about conversions between pointer-to-member types (4.11 "Pointer to member conversions"):

类型为指向cv T类型的B的成员的指针"的右值,其中B为类类型,可以转换为类型为指向cv T类型D的成员的指针"的右值,其中D为B的派生类(第10条).如果B是D的不可访问的(第11条),模棱两可的(10.2)或虚拟的(10.1)基类,则需要此转换的程序格式错误.转换的结果指向与指向转换之前的成员的指针相同的成员,但是它引用基类成员,就好像它是派生类的成员一样.结果引用D的B实例中的成员.由于结果的类型为指向cv T类型D的成员的指针",因此可以使用D对象取消引用.结果与使用D的B子对象解除对B成员的指针的引用相同.

An rvalue of type "pointer to member of B of type cv T", where B is a class type, can be converted to an rvalue of type "pointer to member of D of type cv T", where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D’s instance of B. Since the result has type "pointer to member of D of type cv T", it can be dereferenced with a D object. The result is the same as if the pointer to member of B were dereferenced with the B sub-object of D.

还请注意7.3.3/13使用声明"(添加了强调):

Also note 7.3.3/13 "The using declaration" (emphasis added):

出于重载解析的目的,将使用using声明引入到派生类中的函数视为它们是派生类的成员.特别是,隐式this参数应被视为指向派生类而不是基类的指针. 这对函数的类型没有影响,并且在所有其他方面,函数仍是基类的成员.

现在,生成错误的代码示例:

Now, the code example that generates an error:

// This doesn't:    
void (base_der::* print)(int);
print = &base_der::print; // Compile error here

试图将"D的指针指向"转换为"B的指针指向"-这是错误方向的转换.如果您考虑一会儿,您将了解为什么朝这个方向进行转换并不安全.类型为"B的成员的指针"的变量可能不会与与class D有任何关系的对象一起使用-但是,如果调用类型为"D的成员的指针"的函数(这是void (base_der::* print)(int)是),则可以正确预期this指针将指向D对象.

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 what void (base_der::* print)(int) is), it'll rightly expect that the this pointer will be pointing to a D object.

无论如何,虽然我认为问题的根源在于此转换问题,但我认为您会抱怨可访问性,因为当编译器尝试处理转换时,它首先会检查base的可访问性-尽管由于using声明而可以访问名称base_der::print(这是base::print的别名),但类base仍然不可用.

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 name base_der::print (which is an alias for base::print) is accessible because of the using declaration, class base still isn't.

免责声明:此分析来自对指针成员类型的细微差别经验很少的人.它们是复杂的C ++领域,除非在最简单的情况下,否则很难使用,并且显然存在很多可移植性问题(请参阅Doug Clugston的文章,http://www.codeproject.com/KB/cpp/FastDelegate.aspx ,它已经足够老,以至于现在可能已经解决了许多这些问题,但是我怀疑他们不是).

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).

当您说C ++中的某些内容是较复杂或理解程度较低的领域之一时,这就是很多话.

And when you say that something in C++ is one of the more complex or less-well-understood areas, that's saying a lot.

这篇关于具有私有基础的函数成员指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆