为什么我不能访问作为参数传递给函数的基类的受保护成员变量?

时间:2012-12-05 12:24:46

标签: c++ inheritance

This回答似乎表明它应该有效,为什么我的例子会出现编译错误:

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的建议中将子类更改为公共继承,但没有区别。

3 个答案:

答案 0 :(得分:13)

在这个答案中,我假设您在代码中使用了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章中所述之外的其他访问检查(11.2)如前所述,访问授予受保护的成员是因为引用发生在某个类C的朋友或成员中。如果访问要形成指向成员的指针(5.3.1),则嵌套名称说明符应表示C或从C派生的类。所有其他访问都涉及(可能是隐式的)对象表达式(5.2.5)。 在这种情况下,对象表达式的类应为C或从C派生的类。

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

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

  

派生类只能为自己类型的对象访问基类'protected members [...]这可以防止在一个派生类破坏属于其他派生类的数据时会发生的细微错误。

答案 1 :(得分:2)

基类的受保护成员只能通过其self(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方法。

答案 2 :(得分: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;
    }
};

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