7

这个答案似乎表明它应该可以工作,所以为什么我的示例会引发编译器错误:

class Class1
{
protected:
    long m_memberVar;
};

class SubClass1: public Class1
{
public:
    void PrintMember(Class1 memberToPrintFrom)
    {
        Console::Write("{0}", memberToPrintFrom.m_memberVar); // <-- Compiler error: error C2248: 'BaseClassMemberAccess::Class1::m_memberVar' : cannot access protected member declared in class 'BaseClassMemberAccess::Class1'
    }
};

[编辑] - 根据 Need4Sleep 的建议将子类更改为公共继承,但没有区别。

4

3 回答 3

14

在此答案中,我将假设您public在代码中使用了继承(问题中缺少该继承)。


[C++11: 11.2/1]: public如果使用访问说明符将一个类声明为另一个类的基类(第 10 条)public则基类的public成员可以作为派生类的成员进行访问,而基类的成员可以作为派生类protected的成员进行访问protected. protected如果使用访问说明符将一个类声明为另一个类的基类,则基类的publicprotected成员可以作为protected派生类的成员访问。如果使用访问说明符将一个类声明为另一个类的基类,则基类private的公共和protected成员可以作为private派生类的成员进行访问。

这涵盖了您正在访问同一对象的成员的情况。

然而,protected成员访问有点奇怪,为了访问另一个protected对象的成员,它必须位于相同类型或更派生类型的定义中;在您的情况下,它是派生较少的类型(即基础):

[C++11: 11.4/1]:当非静态数据成员或非静态成员函数是其命名类 (11.2) 的受保护成员时,将应用第 11 节中所述之外的附加访问检查 如前所述,授予对受保护成员的访问权限是因为引用发生在朋友或某个班级的成员中C。如果访问要形成指向成员的指针(5.3.1),则嵌套名称说明符应表示C或派生自 的类C。所有其他访问都涉及(可能是隐式的)对象表达式(5.2.5)。在这种情况下,对象表达式的类应该是C或派生自的类C

也就是说,您必须从Class1成员函数中运行此代码。

Bjarne 在他的书The C++ Programming Language (Sp. Ed.)第 404 页提到了这一点:

派生类只能访问其自身类型的对象的基类的受保护成员 [...] 这可以防止当一个派生类破坏属于其他派生类的数据时可能发生的细微错误。

于 2012-12-05T12:32:14.513 回答
2

派生类只能通过其自身(this)或同一类的另一个对象访问基类的受保护成员,但一般不能通过基类访问。那就是访问,目的是成员的使用被认为仅限于类的实现细节,并且由于您的类正在处理基类,因此在这种特殊情况下它不会知道成员的含义.

您可以使用一种解决方法来获取访问权限,即在基类中提供受保护的 getter 和 setter,通常是静态的,它将为您获取或设置它。

class Class1
{
     protected:
       long m_memberVar; // could even be private

       static long getMemberVar( Class1 const& inst )
       {
          return inst.m_memberVar;
       }

       static long setMemberVar( Class1 & inst, long val )
       {
          inst.m_memberVar = val;
       }

};

现在派生类(但不是通用类)可以使用 getter 和 setter 方法。

于 2012-12-05T12:36:37.253 回答
1

您还可以利用派生对象可以转换为基本对象类型以及对象可以访问其自身类型的任何对象的受保护成员和私有成员这一事实。如果基础对象有一个赋值运算符,可以保证所有需要的成员都被正确复制,你可以这样做:

class Class1
{
protected:
    long m_memberVar;
};

class SubClass1 : public Class1
{
public:
    void PrintMember(Class1 memberToPrintFrom)
    {
        SubClass1 tmpSC;
        auto tmpC1 = dynamic_cast<Class1*>(&tmpSC);
        *tmpC1 = memberToPrintFrom;

        cout << tmpSC.m_memberVar << endl;
    }
};

这效率不高,但可以让您获得基类成员,而无需向基类添加函数。这是使用对象切片将临时派生对象的基础部分替换为传递的基础对象的值。

于 2015-02-18T17:52:59.503 回答