[英]Why can't I access a protected member variable of a base class passed into a function as an argument?
这个答案似乎表明它应该工作,所以我的例子为什么会出现编译器错误:
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的建议中将子类更改为公共继承,但没有区别。
在这个答案中,我将假设您在代码中使用了public
继承(问题中缺少)。
[C++11: 11.2/1]:
如果一个类被声明为使用另一个类的基类(第10节)public
访问说明符 ,这个public
基类的成员是可访问public
派生类的成员和protected
基类的成员是可访问protected
派生类的成员 。 如果使用protected
访问说明符将类声明为另一个类的基类,则基类的public
成员和protected
成员可作为派生类的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在他的书“C ++编程语言”(Sp.Ed。)第404页中提到了这一点:
派生类只能为自己类型的对象访问基类'protected members [...]这可以防止在一个派生类破坏属于其他派生类的数据时可能发生的细微错误。
派生类只能通过其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方法。
您还可以利用以下事实:派生对象可以转换为基础对象类型,并且对象可以访问其自身类型的任何对象的受保护和私有成员。 如果基础对象具有可以保证正确复制所有所需成员的赋值运算符,则可以执行以下操作:
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;
}
};
这样效率不高,但允许您获取基类成员而无需向基类添加函数。 这是使用对象切片将临时派生对象的基本部分替换为传递的基础对象的值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.