Accessing parent's protected variables
我想不出标题的更好措词,所以这有点误导,但是,我并不是在说孩子访问其从父对象继承的变量,这很容易。
我在说的是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Parent {
protected:
Parent *target;
int hp;
}
class Child : public Parent {
public:
void my_func();
}
void Child::my_func() {
target->hp -= 50;
} |
但是,如果我尝试对此进行编译,它将抱怨" hp"在此情况下为"私有"。问题在于孩子不是在尝试访问其自己的父母的变量,而是在访问其他类(可能是也可能不是孩子本身)。
一个对象可以访问同一个类的另一个对象(内存中的两个单独实例)的所有变量和方法(公共,受保护或私有),因此我认为它也可以与此一起工作,因为它继承自试图访问其变量的类,但似乎我不这样做。
有小费吗?
附言不要粗鲁无礼,但是我知道我可以创建get()和set()方法,但是我希望有一种更简洁的方法。
-
此处编写的代码中有许多错误(大写的class关键字错误,继承语法错误等),这些错误肯定是原始代码中存在的错别字。 获取一个无法编译的最小示例,然后将确切的代码复制并粘贴到此处可能会很有用。
-
@Tim我以为你在那儿和自己聊了一会儿,直到我比较了个人资料
-
是的,我应该为此做些事情。 它的名字并不像我想的那么独特。 :-)
-
嗯,是的,我确实没有对此给予过多的关注,并且现在也不允许我对其进行编辑...编辑:我们走了。
-
@安倍:我有同样的问题。 幸运的是,这两个是OP之一,所以我的FF突出了他的名字。 真是一团糟。
特定类的成员函数只能访问基类的受保护成员,这些基类实际上是其自身类类型(或更多派生类型)的对象的基类子对象。
一个类的成员无权访问该基类的其他实例的受保护成员,因此即使在运行时该指针或引用可能是对象,也被禁止通过对基类类型的引用或指针来访问受保护的成员。属于其成员函数正在尝试访问的类的类型。访问控制在编译时强制执行。
例如。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class X
{
protected:
int z;
};
class Y : X
{
public:
int f( const Y& y )
{
return y.z; // OK
}
int g( const X& x )
{
return x.z; // Error, Y::g has no access to X::z
}
}; |
在您的示例中,在表达式target->hp中,对target的访问是合法的,因为您正在访问当前对象的成员(该对象具有该函数所属的类的类型,Child),但是对成员hp的访问是不合法的,因为target的类型不是指向Child的指针,而是指向Parent的指针。
-
也许我在OP中不够清楚,但是我理解这一点。我想知道如果没有get()和set()方法,有什么办法可以做到这一点。
-
@Tim:我的回答是试图帮助解释您的错误假设。有滥用行为,但您应该修复类层次结构,以便拥有所需的访问权限。 stackoverflow.com/questions/3364722/
-
在这种(简化的)情况下,我将如何精确地固定类的层次结构?
-
@Tim:显而易见的解决方案是将hp公开,因为这是您需要的访问权限。
-
嗯也许这过于简单了。除从Parent继承的内容外,我仍然需要" hp"对所有内容均不可访问。附言你如何在盒子里说你的话? (听起来真是愚蠢)
-
@Tim:如果我理解您的意思,则最符合您要求的访问控制是public。 protected对于您的需求而言过于严格。
-
@sbi:谢谢,是的,这是一个错字,而您对变量名的选择正是我的初衷。
-
好吧,公众也太宽松了。我需要的是使所有类型为Parent的对象,或从Parent继承的任何类型(例如Child)的类型都可以访问" hp",但同时没有任何其他类型的其他对象可以访问它。那可能吗?
-
@Tim:出于充分的理由不赞成使用公共数据,而受保护的数据只是对派生类公开的数据。在使用C ++进行编程的15年以上的时间里,我偶尔需要这样做,但在最近十年中很少使用。类状态(数据)应通过其成员函数进行操作,而不是直接摆弄。如果遇到这种需要,我会问自己,基类应该表示什么抽象,以及为什么派生类需要突破该抽象并直接访问基类数据。
-
@Tim:protected和public之间没有任何关系。 C ++中的访问控制相当粗糙,主要是用来指导而不是强制执行。缺少声明每个从Parent派生的类和Parent的friend的能力,没有访问级别与您要执行的操作完全匹配。 public尽可能接近。
-
@sbi:我知道您的意思,但是出于某种原因(对我而言),相同类型的实例可以访问彼此的变量是有意义的。请注意,在我的实际代码中,我只需要读访问权,而不需要写访问权,因为所有写操作都更加复杂,并且放置在方法中。
-
@Tim:那有点骇人听闻,但是不知道您的代码,它很可能是解决任何问题的最佳解决方案。因此,C ++可以帮助您解决问题。但是,对于必须将代码保持10年的人来说,这同样有用,因为您需要通过使用friend或public数据使此黑客明确。
-
@sbi:是的,我认为我只会被迫使用get()和set()方法。
-
@Tim:他们会买你什么?如果将它们公开,则每个人都可以使用它们直接访问您的私有变量。您也可以将变量设置为public。如果将它们设置为受保护的(或私有的),它们将具有受保护的(或私有的)变量相同的问题。不,getter和setter方法要么解决不存在的问题,要么无法解决现有问题。
这很容易(这意味着对OP的明显误解,是因为人们没有花时间阅读OP)。
您只需让孩子成为您需要访问的父母变量的朋友。
或者,您可以让孩子成为父母班的朋友。
这样,任何孩子都可以完全按照您期望的方式访问任何父母的成员变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Child;
class Parent {
protected:
Parent *target;
int hp;
friend void Child::my_func();
}
class Child : public Parent {
public:
void my_func();
}
void Child::my_func() {
target->hp -= 50;
} |
不利的一面是每个孩子都可以访问每个父母的变量。但是,您必须考虑到您的情况,编译器无法知道Parent * target与子实例相同。鉴于您已将其命名为target,所以我希望让每个孩子都能访问每个父级的变量。
这是另一种可能性。让其他所有人使用接口来访问父级,并且只有您的孩子使用实际的父级类。结果是一样的。每个孩子都可以访问每个父母变量。
您将类与实例混淆了。
子级可以访问具有相同INSTANCE的基类的相同成员变量。
-
您不能使类成为变量的朋友。您是要说"课"吗?
-
还要在查尔斯回答时将我对蒂姆的评论记录下来。我对protected所说的对于friend更为真实:它突破了类的抽象,将朋友紧密地耦合到类的实现上。紧耦合总是不好的。尽可能使用friend,但应尽可能少使用。
-
复制粘贴:是的,我可以做到这一点,这是我目前的技巧,但是看起来它打破了继承的"劣势"。您不必与继承自它的每个类成为朋友,以使其正常工作。
-
在那里,完成。很难找到一个完全符合您想要的示例。这就是您如何使一个班级的"单一方法"成为另一班级的朋友。
-
您不能声明class和friend的成员,除非该类已经具有包含有关成员的声明的可见定义。如果您要授予访问权限的类将从试图授予访问权限的类派生,则这是不可能的。
-
我知道您尝试过,但我又不想让孩子成为父母的朋友,因为那样的话,我必须为从父母那里继承的每个类都这样做。我认为我逐渐开始接受我不能做自己想做的事。
-
@Xaade上面的示例无法编译(无效使用不完整类型的struct Child)。经过g ++和clang测试。您可以将整个班级声明为朋友(朋友班级Child)。
嗯,很奇怪,到目前为止,没有人提到这件事,但是您可以声明Child为Parent的朋友(也许是因为您的代码不清楚您想在这里做什么)
1 2 3 4 5 6 7 8 9 10 11
| class Parent {
friend class Child;
protected:
int hp;
}
class Child {
public:
void my_func();
Parent *target;
} |
这将允许访问。或者,您可以编写一个公共的访问器方法:
1 2 3 4 5 6
| class Parent {
public:
get_hp(){return hp;}
protected:
int hp;
} |
-
是的,我可以做到这一点,这是我目前的技巧,但这似乎破坏了继承的"向下性"。您不必与继承自它的每个类成为朋友,以使其正常工作。
-
而且,正如我所说,我知道我可以只使用set()和get()方法,实际上这就是您的示例。我想看看是否有任何类似于Im尝试的方法,如果您不使用继承,您将能够做到。
-
@Tim:正如我在对Charles答案的评论中所说的那样,问题是您想突破基类所代表的抽象。您需要问自己为什么要这么做。
尝试更改为此
1
| Class Child : public Parent |
-
公共继承也会发生同样的问题。
-
Child是从Parent公开继承还是从Parent继承,与Child方法是否试图访问Parent的受保护成员有关,该成员是Child的基类子对象,或者与不是。