Accessing parent's protected variables - c++

I couldn't think of a better wording for the title, so it is a little misleading, however, I am not talking about a child accessing its variables inherited from its parent, which is easy enough.
What I am talking about is this:
class Parent {
protected:
Parent *target;
int hp;
}
class Child : public Parent {
public:
void my_func();
}
void Child::my_func() {
target->hp -= 50;
}
However, if I try to compile this, it will complain about 'hp' being "private in this context". The problem is that the child is not attempting to access its own parent's variables, but some other class', which may or may not be a Child itself.
An object can access all the variables and methods (public, protected, or private) of another object (two separate instances in memory) that is of the same class, so I thought that it would work with this as well, as it inherits from the class whose variables it's attempting to access, but it seems I was incorrect in assuming so.
Any tips?
P.S. Not to be rude or anything, but I know that I can just create get() and set() methods, but I was hoping for a cleaner way.

Member functions of a particular class only have access to protected members of base classes that actually are base class subobjects of objects of their own class type (or more derived types).
Members of one class do not have access to protected members of other instances of that base class and so are also forbidden from accessing protected members through a reference or pointer to the base class type even if at runtime that pointer or reference might be to an object that is of the type of the class whose member function is attempting the access. Access control is enforced at compile time.
E.g.
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
}
};
In your example, in the expression target->hp, the access to target is legal because you are accessing a member of the current object (which has the type of the class of which the function is a member, Child), but the access to the member hp is not legal because the type of target is not a pointer to Child, but a pointer to Parent.

This is so easy (meaning the apparent misunderstanding of the OP, is because people aren't taking the time to read the OP).
You simply make the child a friend of the parent's variable that you need to access.
Or, you can make the child a friend of the parent class.
That way any child has access to any parent's member variables, exactly the way you are expecting.
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;
}
The downside to this is that EVERY child can have access to the variables of EVERY parent. However, you must consider that in your case, the compiler cannot know that Parent *target is the same instance as the child. Given that you named it target, I would expect that having EVERY child have access to variables of EVERY parent is what you want.
Here's another possibility. Have everyone else use an interface to access the parent, and have only your child use the actual parent class. The result is the same though. Every child has access to every parents variables.
You're confusing class with instance.
The child has access to the same member variables of the base class that is of the same INSTANCE.

hmm, strange nobody mentioned this so far, but you could declare Child to be a friend of Parent (maybe because your code isn't very clear about what exactly you want to do here)
class Parent {
friend class Child;
protected:
int hp;
}
class Child {
public:
void my_func();
Parent *target;
}
this would allow access. alternatively you could write an accessor method that's public:
class Parent {
public:
get_hp(){return hp;}
protected:
int hp;
}

Try to change to this
Class Child : public Parent

Related

How to access protected field of parent class from child class [duplicate]

I couldn't think of a better wording for the title, so it is a little misleading, however, I am not talking about a child accessing its variables inherited from its parent, which is easy enough.
What I am talking about is this:
class Parent {
protected:
Parent *target;
int hp;
}
class Child : public Parent {
public:
void my_func();
}
void Child::my_func() {
target->hp -= 50;
}
However, if I try to compile this, it will complain about 'hp' being "private in this context". The problem is that the child is not attempting to access its own parent's variables, but some other class', which may or may not be a Child itself.
An object can access all the variables and methods (public, protected, or private) of another object (two separate instances in memory) that is of the same class, so I thought that it would work with this as well, as it inherits from the class whose variables it's attempting to access, but it seems I was incorrect in assuming so.
Any tips?
P.S. Not to be rude or anything, but I know that I can just create get() and set() methods, but I was hoping for a cleaner way.
Member functions of a particular class only have access to protected members of base classes that actually are base class subobjects of objects of their own class type (or more derived types).
Members of one class do not have access to protected members of other instances of that base class and so are also forbidden from accessing protected members through a reference or pointer to the base class type even if at runtime that pointer or reference might be to an object that is of the type of the class whose member function is attempting the access. Access control is enforced at compile time.
E.g.
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
}
};
In your example, in the expression target->hp, the access to target is legal because you are accessing a member of the current object (which has the type of the class of which the function is a member, Child), but the access to the member hp is not legal because the type of target is not a pointer to Child, but a pointer to Parent.
This is so easy (meaning the apparent misunderstanding of the OP, is because people aren't taking the time to read the OP).
You simply make the child a friend of the parent's variable that you need to access.
Or, you can make the child a friend of the parent class.
That way any child has access to any parent's member variables, exactly the way you are expecting.
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;
}
The downside to this is that EVERY child can have access to the variables of EVERY parent. However, you must consider that in your case, the compiler cannot know that Parent *target is the same instance as the child. Given that you named it target, I would expect that having EVERY child have access to variables of EVERY parent is what you want.
Here's another possibility. Have everyone else use an interface to access the parent, and have only your child use the actual parent class. The result is the same though. Every child has access to every parents variables.
You're confusing class with instance.
The child has access to the same member variables of the base class that is of the same INSTANCE.
hmm, strange nobody mentioned this so far, but you could declare Child to be a friend of Parent (maybe because your code isn't very clear about what exactly you want to do here)
class Parent {
friend class Child;
protected:
int hp;
}
class Child {
public:
void my_func();
Parent *target;
}
this would allow access. alternatively you could write an accessor method that's public:
class Parent {
public:
get_hp(){return hp;}
protected:
int hp;
}
Try to change to this
Class Child : public Parent

If access modifiers are class-level, why does protected seem not to? [duplicate]

Why does this compile:
class FooBase
{
protected:
void fooBase(void);
};
class Foo : public FooBase
{
public:
void foo(Foo& fooBar)
{
fooBar.fooBase();
}
};
but this does not?
class FooBase
{
protected:
void fooBase(void);
};
class Foo : public FooBase
{
public:
void foo(FooBase& fooBar)
{
fooBar.fooBase();
}
};
On the one hand C++ grants access to private/protected members for all instances of that class, but on the other hand it does not grant access to protected members of a base class for all instances of a subclass.
This looks rather inconsistent to me.
I have tested compiling with VC++ and with ideone.com and both compile the first but not the second code snippet.
When foo receives a FooBase reference, the compiler doesn't know whether the argument is a descendant of Foo, so it has to assume it's not. Foo has access to inherited protected members of other Foo objects, not all other sibling classes.
Consider this code:
class FooSibling: public FooBase { };
FooSibling sib;
Foo f;
f.foo(sib); // calls sib.fooBase()!?
If Foo::foo can call protected members of arbitrary FooBase descendants, then it can call the protected method of FooSibling, which has no direct relationship to Foo. That's not how protected access is supposed to work.
If Foo needs access to protected members of all FooBase objects, not just those that are also known to be Foo descendants, then Foo needs to be a friend of FooBase:
class FooBase
{
protected:
void fooBase(void);
friend class Foo;
};
The C++ FAQ summarizes this issue nicely:
[You] are allowed to pick your own pockets, but you are not allowed to pick your father's pockets nor your brother's pockets.
The key point is that protected grants you access to your own copy of the member, not to those members in any other object. This is a common misconception, as more often than not we generalize and state protected grants access to the member to the derived type (without explicitly stating that only to their own bases...)
Now, that is for a reason, and in general you should not access the member in a different branch of the hierarchy, as you might break the invariants on which other objects depend. Consider a type that performs an expensive calculation on some large data member (protected) and two derived types that caches the result following different strategies:
class base {
protected:
LargeData data;
// ...
public:
virtual int result() const; // expensive calculation
virtual void modify(); // modifies data
};
class cache_on_read : base {
private:
mutable bool cached;
mutable int cache_value;
// ...
virtual int result() const {
if (cached) return cache_value;
cache_value = base::result();
cached = true;
}
virtual void modify() {
cached = false;
base::modify();
}
};
class cache_on_write : base {
int result_value;
virtual int result() const {
return result_value;
}
virtual void modify() {
base::modify();
result_value = base::result();
}
};
The cache_on_read type captures modifications to the data and marks the result as invalid, so that the next read of the value recalculates. This is a good approach if the number of writes is relatively high, as we only perform the calculation on demand (i.e. multiple modifies will not trigger recalculations). The cache_on_write precalculates the result upfront, which might be a good strategy if the number of writes is small, and you want deterministic costs for the read (think low latency on reads).
Now, back to the original problem. Both cache strategies maintain a stricter set of invariants than the base. In the first case, the extra invariant is that cached is true only if data has not been modified after the last read. In the second case, the extra invariant is that result_value is the value of the operation at all times.
If a third derived type took a reference to a base and accessed data to write (if protected allowed it to), then it would break with the invariants of the derived types.
That being said, the specification of the language is broken (personal opinion) as it leaves a backdoor to achieve that particular result. In particular, if you create a pointer to member of a member from a base in a derived type, access is checked in derived, but the returned pointer is a pointer to member of base, which can be applied to any base object:
class base {
protected:
int x;
};
struct derived : base {
static void modify( base& b ) {
// b.x = 5; // error!
b.*(&derived::x) = 5; // allowed ?!?!?!
}
}
In both examples Foo inherits a protected method fooBase. However, in your first example you try to access the given protected method from the same class (Foo::foo calls Foo::fooBase), while in the second example you try to access a protected method from another class which isn't declared as friend class (Foo::foo tries to call FooBase::fooBase, which fails, the later is protected).
In the first example you pass an object of type Foo, which obviously inherits the method fooBase() and so is able to call it. In the second example you are trying to call a protected function, simply so, regardless in which context you can't call a protected function from a class instance where its declared so.
In the first example you inherit the protected method fooBase, and so you have the right to call it WITHIN Foo context
I tend to see things in terms of concepts and messages. If your FooBase method was actually called "SendMessage" and Foo was "EnglishSpeakingPerson" and FooBase was SpeakingPerson, your protected declaration is intended to restrict SendMessage to between EnglishSpeakingPersons (and subclasses eg: AmericanEnglishSpeakingPerson, AustralianEnglishSpeakingPerson) . Another type FrenchSpeakingPerson derived from SpeakingPerson would not be able to receive a SendMessage, unless you declared the FrenchSpeakingPerson as a friend, where 'friend' meant that the FrenchSpeakingPerson has a special ability to receive SendMessage from EnglishSpeakingPerson (ie can understand English).
In addition to hobo's answer you may seek a workaround.
If you want the subclasses to want to call the fooBase method you can make it static. static protected methods are accessible by subclasses with all arguments.
You can work around without a friend like so...
class FooBase
{
protected:
void fooBase(void);
static void fooBase(FooBase *pFooBase) { pFooBase->fooBase(); }
};
This avoids having to add derived types to the base class. Which seems a bit circular.

Why couldnt access the child class when child object reference is assigned to parent object pointer

I have a doubt regarding upcasting.
Consider there are two classes, Class Parent and Class child. Child has inherited with parent.
Question:
If i create object pointer for parent, and assigned child object reference. I complied it. the output is "object slicing". Couldn't access the child class specific components
class Parent
{
public:
int i;
void school()
{
std::cout<<"Parent Class::School()"<<std::endl;
}
// virtual goToPlay()
// {
// std::cout<<"Parent Class::goToPlay()"<<std::endl;
// }
};
class Child:public Parent
{
public:
int j;
void goToPlay()
{
std::cout<<"Child Class::goToPlay()"<<std::endl;
}
};
int main()
{
Parent *mParent;
Child mChild;
mParent = &mChild;
mParent->school();
mParent->goToPlay(); //Error
couldnt access goToPlay() API. If i create a virtual function of goToPlay() in Parent Class, then its is accessible. Can any one tell whats the reason?
You explicitly declare Parent * mParent, so your object is treated as an instance of Parent. In many use cases, this is exactly what you want - you provide a proper interface for doing something, and the concretely used implementation is of no concern to the end user:
class employee
{
public:
virtual double get_salary_in_usd() const = 0;
virtual ~employee() {}
};
class software_developer : public employee
{
public:
double get_salary_in_usd() const { return 100000.; /* i wish */ }
void be_awesome() {}
~software_developer() {}
};
void print_salary(std::shared_ptr<employee> const & emp)
{
std::cout << "This employee earns $" << emp->get_salary_in_usd()
<< " a month." << '\n';
}
In some cases however, you need to tell at runtime, whether your pointer is a certain child of your base class. This is what dynamic_cast is for:
software_developer me;
employee * me_generalized = &me;
software_developer * me_again = dynamic_cast<software_developer *>(
me_generalized);
if(me_again != nullptr)
{
me_again->be_awesome();
}
Note that dynamic_cast can return nullptr if the pointer could not be casted. Also note that this happens with RTTI during runtime, and slows down your application. Avoid using this whenever possible.
Since your pointer type is Parent then only the Parent's api will be accessible since that is what you tell the compiler. (i.e. this pointer points to a Parent object).
In your case a virtual method will make the correct implementation being called. (this is called late binding and it is done during run time via hidden tables in the instance to find the correct address of the method's implementation which in your case is the Child implementation since mParent points to a Child instance)
In order to use Child::goToPlay() through a pointer-to-Parent, Parent would have to declare its own function goToPlay(), and this function would have to be marked virtual. Your Child class then overrides that function.
Then, when you call goToPlay() on the Parent pointer, the Child function is magically invoked instead.
However, you can't just do this for arbitrary functions that doesn't even exist in Parent.

accessing a protected member of a base class in another subclass

Why does this compile:
class FooBase
{
protected:
void fooBase(void);
};
class Foo : public FooBase
{
public:
void foo(Foo& fooBar)
{
fooBar.fooBase();
}
};
but this does not?
class FooBase
{
protected:
void fooBase(void);
};
class Foo : public FooBase
{
public:
void foo(FooBase& fooBar)
{
fooBar.fooBase();
}
};
On the one hand C++ grants access to private/protected members for all instances of that class, but on the other hand it does not grant access to protected members of a base class for all instances of a subclass.
This looks rather inconsistent to me.
I have tested compiling with VC++ and with ideone.com and both compile the first but not the second code snippet.
When foo receives a FooBase reference, the compiler doesn't know whether the argument is a descendant of Foo, so it has to assume it's not. Foo has access to inherited protected members of other Foo objects, not all other sibling classes.
Consider this code:
class FooSibling: public FooBase { };
FooSibling sib;
Foo f;
f.foo(sib); // calls sib.fooBase()!?
If Foo::foo can call protected members of arbitrary FooBase descendants, then it can call the protected method of FooSibling, which has no direct relationship to Foo. That's not how protected access is supposed to work.
If Foo needs access to protected members of all FooBase objects, not just those that are also known to be Foo descendants, then Foo needs to be a friend of FooBase:
class FooBase
{
protected:
void fooBase(void);
friend class Foo;
};
The C++ FAQ summarizes this issue nicely:
[You] are allowed to pick your own pockets, but you are not allowed to pick your father's pockets nor your brother's pockets.
The key point is that protected grants you access to your own copy of the member, not to those members in any other object. This is a common misconception, as more often than not we generalize and state protected grants access to the member to the derived type (without explicitly stating that only to their own bases...)
Now, that is for a reason, and in general you should not access the member in a different branch of the hierarchy, as you might break the invariants on which other objects depend. Consider a type that performs an expensive calculation on some large data member (protected) and two derived types that caches the result following different strategies:
class base {
protected:
LargeData data;
// ...
public:
virtual int result() const; // expensive calculation
virtual void modify(); // modifies data
};
class cache_on_read : base {
private:
mutable bool cached;
mutable int cache_value;
// ...
virtual int result() const {
if (cached) return cache_value;
cache_value = base::result();
cached = true;
}
virtual void modify() {
cached = false;
base::modify();
}
};
class cache_on_write : base {
int result_value;
virtual int result() const {
return result_value;
}
virtual void modify() {
base::modify();
result_value = base::result();
}
};
The cache_on_read type captures modifications to the data and marks the result as invalid, so that the next read of the value recalculates. This is a good approach if the number of writes is relatively high, as we only perform the calculation on demand (i.e. multiple modifies will not trigger recalculations). The cache_on_write precalculates the result upfront, which might be a good strategy if the number of writes is small, and you want deterministic costs for the read (think low latency on reads).
Now, back to the original problem. Both cache strategies maintain a stricter set of invariants than the base. In the first case, the extra invariant is that cached is true only if data has not been modified after the last read. In the second case, the extra invariant is that result_value is the value of the operation at all times.
If a third derived type took a reference to a base and accessed data to write (if protected allowed it to), then it would break with the invariants of the derived types.
That being said, the specification of the language is broken (personal opinion) as it leaves a backdoor to achieve that particular result. In particular, if you create a pointer to member of a member from a base in a derived type, access is checked in derived, but the returned pointer is a pointer to member of base, which can be applied to any base object:
class base {
protected:
int x;
};
struct derived : base {
static void modify( base& b ) {
// b.x = 5; // error!
b.*(&derived::x) = 5; // allowed ?!?!?!
}
}
In both examples Foo inherits a protected method fooBase. However, in your first example you try to access the given protected method from the same class (Foo::foo calls Foo::fooBase), while in the second example you try to access a protected method from another class which isn't declared as friend class (Foo::foo tries to call FooBase::fooBase, which fails, the later is protected).
In the first example you pass an object of type Foo, which obviously inherits the method fooBase() and so is able to call it. In the second example you are trying to call a protected function, simply so, regardless in which context you can't call a protected function from a class instance where its declared so.
In the first example you inherit the protected method fooBase, and so you have the right to call it WITHIN Foo context
I tend to see things in terms of concepts and messages. If your FooBase method was actually called "SendMessage" and Foo was "EnglishSpeakingPerson" and FooBase was SpeakingPerson, your protected declaration is intended to restrict SendMessage to between EnglishSpeakingPersons (and subclasses eg: AmericanEnglishSpeakingPerson, AustralianEnglishSpeakingPerson) . Another type FrenchSpeakingPerson derived from SpeakingPerson would not be able to receive a SendMessage, unless you declared the FrenchSpeakingPerson as a friend, where 'friend' meant that the FrenchSpeakingPerson has a special ability to receive SendMessage from EnglishSpeakingPerson (ie can understand English).
In addition to hobo's answer you may seek a workaround.
If you want the subclasses to want to call the fooBase method you can make it static. static protected methods are accessible by subclasses with all arguments.
You can work around without a friend like so...
class FooBase
{
protected:
void fooBase(void);
static void fooBase(FooBase *pFooBase) { pFooBase->fooBase(); }
};
This avoids having to add derived types to the base class. Which seems a bit circular.

C++ how to call a parent class method from contained class?

I am trying to make a call to a Parent class method from a contained object, but have no luck with the following code. What is the standard way to do it?
I have searched around and this seems to work for inherited objects, but not for contained objects. Is it right to call it a Parent class even? Or is it called an Owner class?
class Parent{
private:
Child mychild;
public:
void doSomething();
}
class Child{
public:
void doOtherThing();
}
void Child::doOtherThing(){
Parent::doSomething();
}
A contained object has no special access to the class that contains it, and in general does not know that it is contained. You need to pass a reference or a pointer to the containing class somehow - for example:
class Child{
public:
void doOtherThing( Parent & p );
};
void Child::doOtherThing( Parent & p ){
p.doSomething();
}
The child has no connection to the parent class at all. You'll have to pass 'this' down to the child (probably in the constructors) to make this work.
If the child needs to interact with the parent, then it will need a reference to that object; at present, the child has no notion of an owner.