I have two classes like this:
#include <iostream>
class A {
public:
class B {
public:
void printX(void) const { std::cout << A::x << std::endl; }
};
private:
int x;
};
Obviously this piece of code doesn't work because B can't access x, but is there a way to make it work?
I've tried using friend class keyword in both classes like this:
class A {
public:
class B {
public:
friend class A;
void printX(void) const { std::cout << A::x << std::endl; }
};
friend class B;
private:
int x;
};
But it didn't work either, and I can't figure out if it's even possible.
According to the C++ 17 Standard (14.7 Nested classes)
1 A nested class is a member and as such has the same access rights as
any other member. The members of an enclosing class have no special
access to members of a nested class; the usual access rules (Clause
14) shall be obeyed.
The problem with the provided code is that x is not a static data member of the class A. You need to provide an object of the class A the data member x of which will be accessed within an object of the nested class.
For example
class A {
public:
class B {
public:
void printX( const A &a ) const { std::cout << a.x << std::endl; }
};
private:
int x;
};
A::B().printX( A() );
As the error message should tell you, A::x isn’t a static member so you need an object instance to access it. If you add a reference to instance of A to B::A, you can use that to access A::x.
For example, the following works:
class A {
public:
class B {
public:
B(A const& a) : a(a) {}
void printX(void) const { std::cout << a.x << std::endl; }
private:
A const& a;
};
private:
int x;
};
Note that using a reference member has several implications. Notably, you can now no longer reassign instances of type A::B, nor are its instances movable. As a consequence, it’s often convenient to hold a pointer rather than a reference to A inside A::B. Either way, you’ll need to ensure that instances of A::B do not outlive the A instance they refer to, otherwise you end up with a dangling reference.
Related
Here is what UML looks like CLASS UML
ClassA has an pointer to ClassB, and ClassB has a pointer to ClassC. I was wondering if I can access functions of ClassA in ClassC without inheriting ClassA.
Q: I was wondering if I can access functions of ClassA in ClassC without inheriting ClassA.
A: Yes, it is possible to access functions of ClassA in ClassC. Either by calling static member functions of classA or by providing specific instance of classA to ClassC. It may look like that classA can be accesed by following the pointers in reverse direction (ClassC to ClassB to ClassA) but that is not possible. Pointers point to values only in one direction.
This is interesting question about differences between a class and instances of class (objects). The following example shows why there is no classA::callAnyMethod():
#include <iostream>
class B;
class C;
class A
{
public:
A(B *next, int value) : next_(next), value_(value) { }
void af1() const { std::cout << value_ << "\n"; }
static void af2() { std::cout << staticValue << "\n"; }
protected:
B *next_;
int value_;
static int staticValue;
};
int A::staticValue = 3;
class B
{
public:
B(C *next) : next_(next) { }
protected:
C *next_;
};
class C
{
public:
void cf1(const A &a) { a.af1(); }
void cf2() { A::af2(); }
};
int main()
{
C c;
B b(&c);
A a1(&b, 1);
A a2(&b, 2);
// a1 is first instance of class A.
// One 'A::value_' is defined in a1 and is equal to 1.
c.cf1(a1);
// a2 is second instance of class A.
// Second 'A::value_' is defined in a2 and is equal to 2.
c.cf1(a2);
// Without specific instance of class A, we can use only static member
// 'A::staticValue' which is defined at file scope and is equal to 3.
// 'A::staticValue' is not part of objects (instances) of class A.
c.cf2();
return 0;
}
I have an unexpected behavior using the friend keyword and a reference. Here is the code :
#include <iostream>
class Modifier;
class A{
private:
int _a;
friend Modifier;
};
class B : public A {};
class Modifier
{
public:
void f(A& i) { i._a = 10; std::cout << i._a << std::endl; }
};
int main()
{
Modifier m;
B b;
m.f(b);
}
// Output
// 10
B shouldn't be able to modify the variable _a. Can someone explain me how it is possible ?
B shouldn't be able to modify the variable _a
_a and the object that contains it are non-const, so _a can be modified. Declaring a member private doesn't prevent a variable from being modified. Access specifier only affects the scopes where the name of the variable is accessible.
The class B doesn't modify the variable _a. It is Modifier::f that modifies _a variable (which is member of A base sub object of variable b). Modifier is a friend of class A, so members functions of Modifier have access to privately declared names of A. Having access means that it can use the name A::_a.
B is already unable to modify _a, as it's declared private in B. It's only accessible in A. If you need to read _a from B, use protected getter:
class A {
protected:
auto get_a() const { return _a; }
private:
int _a;
friend Modifier;
};
A friend class can access private and protected members of other class in which it is declared as friend. So, _a can be modified by any method of class Modifer. However, B can not modify _a because it is defined as private in class A. For example, if you would implement the method f in class B, then you would get compiler error which says 'int A::_a' is private
class B : public A {
void f(A& i) { i._a = 10; std::cout << i._a << std::endl; }
};
This is about "protected", which is explained as: "When a class inherits another one, the members of the derived class can access the protected members inherited from the base class." However, look at this code:
class Base {
public:
Base( int m ) : member(m){}
protected:
int member;
};
class Derived : public Base { // one of several subclasses
public:
Derived( int m ) : Base(m), value(10) {}
int diff( Base x ){
return value - x.member;
}
private:
int value;
};
Derived accesses "x.member", which is protected in its Base class, right? But the compiler flags an error, "Base::member is protected". And, after mulling this over for a minute, I had to agree with the compiler.
And here comes the question: How do I make this work, with a minimum loss of information hiding?
Clearly, making "member" public compiles, but it's against the original intent.
Using the "friend" mechanism in Base to let subclasses access "member" (and everything else that's private and protected) is even worse (apart from the dumb binding of a superclass to its own subclasses - a maintenance nightmare).
In the simple example, a public int getMember(){ return member; } would be acceptable. But if member's type is a X*, the best you can do is a public const X* getMember(){...}.
Did I miss something?
You can keep the protected attributes, add the getter functions as you mentioned. As for a protected pointer attribute, the getter would make sure that int (or a const ref for a large object) is returned and you can do the difference in a function template that takes Derived and Base arguments then (getters give you the values for the calculation).
Protecting data attributes allows direct access to the protected attribute within the derived class. What you tried is to access a private attribute of another object. This part of your code:
int diff( Base x ){
return value - x.member;
}
would be equivalent to writing this in main:
Base x;
cout << x.member << endl;
Here is an example of how to solve the problem using the option 3 you suggested yourself, with a derived class PointerDerived that is using pointers for the storage:
#include <iostream>
class Base {
public:
Base( int m ) : member(m){}
int getMember() const
{
return member;
}
protected:
int member;
};
class Derived : public Base { // one of several subclasses
public:
Derived( int m ) : Base(m), value(10) {}
int getValue() const
{
std::cout << "protected = " << member << std::endl;
return value;
}
private:
int value;
};
class PointerDerived : public Base { // one of several subclasses
public:
PointerDerived( int m ) : Base(m), value(new int (10)) {}
int getValue() const
{
std::cout << "protected = " << member << std::endl;
return *value;
}
~PointerDerived()
{
delete value;
value = nullptr;
}
private:
int* value;
};
template<typename Derived, typename Base>
int diff(const Derived& d, const Base& b)
{
return d.getValue() - b.getMember();
}
using namespace std;
int main(int argc, const char *argv[])
{
PointerDerived p(23);
Base q(1);
cout << diff(p, q) << endl;
return 0;
}
Compile the program with -std=c++11 because of the nullptr, or change it to NULL.
You make the diff a function template, so that you don't have to overload it for each and every derived class, and you let the derived class handle the storage and access to it as does for example PointerDerived.
You can use a static protected accessor:
class Base {
public:
Base( int m ) : member(m){}
private:
int member;
protected:
static int GetMember(const Base &b)
{ return b.member; }
};
class Derived : public Base { // one of several subclasses
public:
Derived( int m ) : Base(m), value(10) {}
int diff( Base &x ){ //beware of your slicing!
return value - GetMember(x);
}
private:
int value;
};
Now let me add my idea of why C++ access control works this way...
Access control in C++ is not about information hiding. It is about encapsulation. That is, plainly speaking, you filter out the access to any member that can break the class if used incorrectly.
In an ideal class
public members cannot be used to break the object.
private members know what they are doing.
As you see, in my scheme there is little place for protected members:
protected members are used to implement the inheritance interface, if any.
And even less place for protected member variables.
So make your variable private, and write a protected accessor. The accessor must be static to be able to be used from the derived object.
class A
{
class B
{
int x;
}
public:
void printX() { std::cout << ????; }
}
How can I access the x variable from the A class function? I can't make it static either...
I tried everything but it either tells me I need an object in order to access it or the compiler doesn't find the function.
it either tells me I need an object [...]
Think about that. Because that's exactly what the problem is here.
If you instantiate an A, you don't also get a B. A nested class isn't a member variable of the enclosing class. It's really just another way to change the namespace of a class.
So, you need an instance of B. Perhaps a member of A?
class A
{
class B
{
public:
int x;
} mB;
public:
void printX() { std::cout << mB.x; }
};
You don't ever declare an instance of the class B inside A. You need to do something like this:
class A
{
class B
{
public:
int x;
};
B b;
public:
void printX() { std::cout << b.x; }
};
You don't. You do need an object in order to use the x variable. You could, however make it static. The problem with your example is x is not public. Placing B inside A does not make B part of A, it only changes B's scope.
From this example it kinda looks like you're after inheritance instead. This would give you the effect you're after ( access to all B's methods and variables without making an object. )
Class B
{
protected:
int x;
}
Class A : B
{
void printX() { std::cout << x; }
}
#include <string>
#include <iostream>
class a { public: int x;};
class b : public a {public: int x; } ;
int main()
{
b bee;
bee.x = 3;
a ay = bee;
std::cout << std::endl << ay.x << std::endl;
}
The code above compiles fine in clang 3.0 and g++ 4.5. However the output is junk (--i.e., not three). Since the compiler doesn't seem to mind, how do I get the code to behave ?
Secondly, If there is some way to make the above slice / conversion to work correctly, how bad would it be if I then did the following, provided a good reason to do it exists :
class c : public a { public: uint64_t x; };
Why I am interested in these semantics.
The reason I want to do this is this. I have a two class heirachies, where one heirarchy (the parent) aggregages objects, on the same heirarchy level, from the other(the child). I use a custom container for the aggregation. I want to typedef the container in the parent class (the typedefs have the same name), and declare the container with the same name at each level of the parent.
The class heirarchies are designed to contain less information at lower levels ( the base classes hold the least), therefore slicing makes perfect sense here.
Edit:
There you go, this should clear things up.
class A { int x; };
class B : public A {int y;};
class Ap {std::vector<A> entries;};
class Bp : Ap{std::vector<B> entries;};
The child B has more members than the child class A. However, I wan't to present a uniform interface for code that is only interested in the members of class A.
There is no way to do that if you directly set b::x. a::x and b::x are two different members, and the latter hides the former.
You can still access a::x on an object of type b with static_cast<a&>(bee).x = 3, but the fundamental problem is that the values of a::x and b::x on an object of type b are not synchronized.
If you abstract access to both x members with a "property getter/setter", then you can arrange for the setter on the derived class to also update the member of the base class. Or (maybe this is more appropriate?) you can make the member of the base class protected and use it from the derived class directly, slicing as you need just before returning from the getter.
huh ! its a bit complicated no ?
why don't you use :
class a
{
virtual void set( int value ) { x = value; }
protected :
int x;
};
class b : public a
{
virtual void setA( int value ) { a::x = value; }
or
virtual void setA( int value ) { b::x = value; }
or
virtual void setA( int value ) { a::x = value; b::x = value; }
protected:
int x;
} ;
There are two ways of constructing a software design; one way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.
C.A.R.Hoare
According to Jon's answer, Since a::x and b::x are separate variables, furthermore since b::x masks a::x, if you wanted to get the correct semantics you need to provide a copy conversion constructor. The following code does the trick.
#include <string>
#include <iostream>
class b;
class a {
public:
a();
a(const b & bee);
int x;
};
class b : public a {public: int x; } ;
a::a() {}
a::a(const b & bee)
{
x = bee.x;
}
int main()
{
b bee;
bee.x = 3;
a ay = bee;
std::cout << std::endl << ay.x << std::endl;
}
Maybe try something like this:
class A { int x; };
class B : public A {int y;};
class Ap {
public:
void Append(A *pa)
{
entries.push_back(pa);
}
A *GetA(size_t nIndex)
{
return entries.at(nIndex);
}
private:
std::vector<*A> entries;
};
class Bp : Ap
{
public:
B *GetB(size_t nIndex)
{
return dynamic_cast<B*>(GetA(nIndex));
}
};