Say you are given the following UML class diagram:
Can a variable of type Mystery invoke the function DoSomething()?
I understand that an object (say Mystery X;) could call GetA() to access the private variable int a
and to access the public variable int b all you need is X.b
but how could this object, X, access the private function DoSomething()
if it's even possible?
I had difficulty understanding exactly what you are asking, but I think I've figured it out.
If you are asking if, given the following declaration:
class Mystery
{
/*...*/
private:
void DoSomething();
};
you can do something like this:
Mystery m;
m.DoSomething();
...then the answer is no. You cannot call private member functions (or refer to private member variables) from outside the context of the class. Only another member function of Mystery can call the privates. For example:
void Mystery::Foo()
{
DoSomething(); // this would be possible if Foo() is a member of Mystery
}
EDIT:
Not only can you not call private members from outside the class, you also can't call them from subclasses. For example, this is not valid:
class Base
{
private:
void Foo() {};
};
class Child : public Base
{
public:
void Bar()
{
Foo(); // ERROR: Can't call private method of base class
}
};
There is one (edit - for completeness sake, there is more than one, see the comments) weird way that a private member function could be called outside your class, but it requires a little bit of a contrived example, where you can return a pointer to this function:
class Mystery;
typedef void (Mystery::*fptr)();
class Mystery{
void DoSomething() {};
public:
static fptr GetPrivateDoSomething()
{
return &DoSomething;
}
};
int main(int argc, char *argv[])
{
Mystery m;
fptr ds = Mystery::GetPrivateDoSomething();
(m.*ds)();
return 0;
}
That being said, don't do this. Private methods are private for a reason - they embody hidden aspects of the design, and were never meant to be a part of the exposed interface. That means that they could be subject to a change in behavior, or even complete removal. Additionally, doing these sorts of shenanigans can lead to code that is highly and awkwardly coupled, which is undesirable.
THAT being said, I have indeed used this and it works quite well, although it was in an entirely different context where it helped to reduce coupling (it was in a highly-modular event registration scheme, if you were wondering).
Any method inside the class is allowed to access the private variables and methods. It works exactly like calling any other method, its just that the compiler will give you an error if you try to do it from outside the class.
Related
I'm confused as to why the C++ compiler won't accept this:
class Foo {
private: void Baz() { }
};
class Bar {
public: void Baz() {
};
class FooBar : public Foo, public Bar { };
void main() {
FooBar fb;
fb.Baz();
}
The error gcc gives is:
request for member ‘Baz’ is ambiguous
candidates are: void Bar::Baz()
void Foo::Baz()
but isn't it obvious that I want Bar::Baz(), since Foo::Baz() is private? Why won't the compiler disambiguate here?
Name resolution works in two stages. First the name is looked up then the name is checked for access. If the name look up is ambiguous then the access is never considered.
As to why, maybe it's a deliberate language design, but I think more likely it's just to simplify the process of resolving names. The rules are fiendishly complicated already.
It's not obvious - you might have wanted to call the private member (if that was possible).
Formally, the language rules say that the name is resolved first and the best overload is selected. Only after that is there a check for accessibility.
In order to allow this, it would need to consider whether or not you are in a context that allows you to call a private method or not. If this were allowed then the call:
fb.Baz()
could have completely different functionality depending on whether you were calling it from a public or private context. And that's not really inline with the way the language works.
As others have said, first the name is looked up, then access restrictions are applied. You can work around this by explicitly calling the method you wish, as in
fb.Bar::Baz()
Access restrictions don't affect inheritance. You always inherit everything from all base classes. In your case that may seem unnecessary, but consider a slightly modified version where the private function is virtual:
class Base
{
virtual void secret_power() { /* innocent default */ }
public:
void use_me() { secret_power(); }
};
class Derived : public Base
{
virtual void secret_power() { /* overriding implementation here */ }
};
Now for any Base& you can always call the non-virtual public interface use_me(), but your derived classes provide the implementation by means of a private virtual.
A class Base, which I have no control over, has a function that accepts a member pointer to any class function. It is meant to be used as follows:
class Derived : public Base {
void bindProperties() {
Base::bindProperty("answer", &Derived::getAnswer);
}
int getAnswer() const { return 42; }
};
Some way (that I neither know nor care about), Base stores this pointer and later allows me to call Derived::get("answer") (of course, this is a simplified situation).
The down side is, that we tried to be smart in the past, and used multiple inheritance:
class ICalculator {
virtual int getAnswer() const;
};
template<class T>
class LifeAndUniverseCalculator : public T, public ICalculator {
virtual int getAnswer() const /* override */ { return 42; }
void bindProperties() {
T::bindProperty("answer", &ICalculator::getAnswer); // (*)
}
};
thinking that the multiple inheritance is not bad, as long as we only use it to inherit an interface and only have one "concrete" base class.
The templating is because sometimes we want to derive from Base and sometimes from one of its derived classes (which I also don't have access to) - if that is irrelevant you can pretend I wrote Base instead of T and drop the template.
Anyway, the problem I am having now, is that when I call
LifeAndUniverseCalculator calc;
calc.bindProperties();
int answer = calc.get("answer");
I get gibberish. I figured it may be something with pointers into vtables, so I tried replacing
T::bindProperty("answer", &ICalculator::getAnswer);
by
T::bindProperty("answer", &LifeAndUniverseCalculator::getAnswer);
hoping that it would calculate the offset correctly, but clearly that does not work (as you have figured out by now, I am really second guessing how this all works).
I thought of some options, such as
getting rid of the multiple inheritance and putting everything in ICalculator directly in LifeAndUniverseCalculator (it's the only derived class)
creating wrapper functions for all ICalculator stuff in LifeAndUniverseCalculator, e.g. LifeAndUniverseCalculator::Calculator_GetAnswer just calls ICalculator::GetAnswer.
I'd like to know
Preferably, is there a way to fix the line marked with (*) in a simple way?
If not, what is the best solution (one of the alternatives above, or something else)?
If I were able to contact the author of class Base and they would be willing and able to change their class, what specifically would I need to ask, if you are able to say something sensible based on my description.
If you need a MCVE, there is one which I think captures the problem on IDEOne.
In your MCVE, the function A::bindFunction (analogous to Base::bindProperty in your simplified code) force casts a member of function of B to a member function of A. This strikes me as the root problem. This can be fixed by changing the type of A::f to be an std::function<int(void)>:
class A
: public ABase {
public:
// int a, b;
class Unknown{};
typedef int(A::*Function)();
template<typename T, typename Func>
void bindFunction(T* owner, Func myf) {
f = std::bind(myf,owner);
}
int call() {
return f();
}
//Function f;
std::function<int(void)> f;
};
...
class Combined
: public A, public B {
public:
Combined(int value) : B(value), A() {}
virtual void /*A::*/bind() /* override */ {
A::bindFunction( this, &Combined::getValue );
}
};
With only this change, your MCVE works, printing out
The answer to Life, The Universe and Everything is 42
However, I recognize that the code that I changed belongs to a class that you've explicitly mentioned that you cannot modify. Is this indeed what Base does -- it casts member functions of other classes to member functions of itself? (Or perhaps, while my fix makes the code work, I've misidentified the problem).
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 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.
I'm confused as to why the C++ compiler won't accept this:
class Foo {
private: void Baz() { }
};
class Bar {
public: void Baz() {
};
class FooBar : public Foo, public Bar { };
void main() {
FooBar fb;
fb.Baz();
}
The error gcc gives is:
request for member ‘Baz’ is ambiguous
candidates are: void Bar::Baz()
void Foo::Baz()
but isn't it obvious that I want Bar::Baz(), since Foo::Baz() is private? Why won't the compiler disambiguate here?
Name resolution works in two stages. First the name is looked up then the name is checked for access. If the name look up is ambiguous then the access is never considered.
As to why, maybe it's a deliberate language design, but I think more likely it's just to simplify the process of resolving names. The rules are fiendishly complicated already.
It's not obvious - you might have wanted to call the private member (if that was possible).
Formally, the language rules say that the name is resolved first and the best overload is selected. Only after that is there a check for accessibility.
In order to allow this, it would need to consider whether or not you are in a context that allows you to call a private method or not. If this were allowed then the call:
fb.Baz()
could have completely different functionality depending on whether you were calling it from a public or private context. And that's not really inline with the way the language works.
As others have said, first the name is looked up, then access restrictions are applied. You can work around this by explicitly calling the method you wish, as in
fb.Bar::Baz()
Access restrictions don't affect inheritance. You always inherit everything from all base classes. In your case that may seem unnecessary, but consider a slightly modified version where the private function is virtual:
class Base
{
virtual void secret_power() { /* innocent default */ }
public:
void use_me() { secret_power(); }
};
class Derived : public Base
{
virtual void secret_power() { /* overriding implementation here */ }
};
Now for any Base& you can always call the non-virtual public interface use_me(), but your derived classes provide the implementation by means of a private virtual.