5

有人可以解释一下为什么这段代码:

class safe_bool_base
{ //13
    protected:

        typedef void (safe_bool_base::*bool_type)() const;

        void this_type_does_not_support_comparisons() const {} //18

        safe_bool_base() {}
        safe_bool_base(const safe_bool_base&) {}
        safe_bool_base& operator=(const safe_bool_base&) { return *this; }
        ~safe_bool_base() {}
};

template <typename T=void> class safe_bool : public safe_bool_base
{
    public:

        operator bool_type() const
        {
            return (static_cast<const T*>(this))->boolean_test() ? &safe_bool_base::this_type_does_not_support_comparisons : 0;
        }

    protected:

        ~safe_bool() {}
};

template <> class safe_bool<void> : public safe_bool_base
{
    public:

        operator bool_type() const
        {
            return (boolean_test() == true) ? &safe_bool_base::this_type_does_not_support_comparisons : 0; //46
        }

    protected:

        virtual bool boolean_test() const = 0;
        virtual ~safe_bool() {}
};

产生以下编译器错误?

c:\project\include\safe_bool.hpp(46) : error C2248: 'safe_bool_base::this_type_does_not_support_comparisons' : cannot access protected member declared in class 'safe_bool_base'
c:\project\include\safe_bool.hpp(18) : see declaration of 'safe_bool_base::this_type_does_not_support_comparisons'
c:\project\include\safe_bool.hpp(13) : see declaration of 'safe_bool_base'

由于两个safe_bool模板都派生自safe_bool_base,我不明白为什么不能访问基类的受保护成员。

我错过了什么吗?

4

3 回答 3

9

这可能会有所帮助(在非模板情况下也可以重现)

struct A{
protected:
    void f(){}
};

struct B : A{
    void g(){&A::f;}        // error, due to Standard rule quoted below
};

int main(){
}

VS给出“'A::f':无法访问在类'A'中声明的受保护成员”

对于相同的代码,Comeau 给出

“ComeauTest.c”,第 7 行:错误:受保护的函数“A::f”(在第 3 行声明)无法通过“A”指针或对象访问 void g(){&A::f;} ^

“ComeauTest.c”,第 7 行:警告:表达式无效 void g(){&A::f;}

这是实现预期意图的固定代码

struct A{
protected:
    void f(){}
};

struct B : A{
    void g(){&B::f;}        // works now
};

int main(){
}

那么,为什么第一个代码片段不起作用?

这是因为 C++ Standard03 中的以下规则

11.5/1-“当派生类的友元或成员函数引用基类的受保护的非静态成员函数或受保护的非静态数据成员时,除了前面第 11.102 节中描述的那些之外,还应用访问检查)除非形成指向成员的指针(5.3.1),访问必须通过派生类本身(或从该类派生的任何类)的指针、引用或对象(5.2.5)。如果访问要形成一个指向成员的指针,嵌套名称说明符应命名派生类(或从该类派生的任何类)。

因此,如下更改运算符函数中的返回值

return (boolean_test() == true) ? &safe_bool<void>::this_type_does_not_support_comparisons : 0; //46 

return (static_cast<const T*>(this))->boolean_test() ? &typename safe_bool<T>::this_type_does_not_support_comparisons : 0; 

编辑2:请忽略我的解释。大卫是对的。这就是归结为。

struct A{
protected:
    int x;
};

struct B : A{
    void f();
};

struct C : B{};

struct D: A{            // not from 'C'
};

void B::f(){
    x = 2;         // it's own 'A' subobjects 'x'. Well-formed

    B b;
    b.x = 2;       // access through B, well-formed

    C c;
    c.x = 2;       // access in 'B' using 'C' which is derived from 'B', well-formed.

    D d;
    d.x = 2;       // ill-formed. 'B' and 'D' unrelated even though 'A' is a common base
}

int main(){} 
于 2010-09-07T10:07:08.187 回答
1

我认为这与模板无关。您的示例代码可以简化为此,它仍然给出等效的错误:

class A
{
    protected:
        typedef void (A::*type)() const;
        void foo() const {}
};


class B : public A
{
    public:
        operator type() const
        {
            return &A::foo;
        }
};

我相信问题是您不能将成员函数指针返回到公共接口中的受保护成员。编辑:不是真的......

于 2010-09-07T09:49:25.677 回答
0

Chubsdad 的回答澄清了您关于模板专业化为什么会出错的问题。

现在以下 C++ 标准规则

14.7.2/11通常的访问检查规则不适用于用于指定显式
实例化
的名称。[注意:特别是,函数
声明器中使用的模板参数和名称(包括参数类型、返回类型和异常规范)可能是
通常无法访问的私有类型或对象,并且模板可能是
成员模板或成员函数通常无法访问。——尾注]

将解释为什么通用模板实例化不会引发错误。即使您有私有访问说明符,它也不会抛出。

于 2010-09-07T11:45:57.747 回答