Say I have an incredibly contrived class defined as follows:
class Outer {
public:
struct Inner {
Inner(int innerValue) : foo(innerValue) {};
int foo;
};
Outer(int innerValue) : _inner(innerValue) {};
const Inner& getInner() const {
return _inner;
};
private:
Inner _inner;
};
I want Outer to be the only class capable of constructing an instance of Inner, but in such a way that other classes/functions can access _inner.foo when passed a reference to _inner through Outer::getInner(). Is this possible? Is there a better way of achieving equivalent functionality?
I'm aware of two solutions to such a problem which I'd like to demonstrate and compare.
Solution 1 (friend):
Using the friend keyword, you can allow another class to access your private functions. (Use carefully.)
You can make the constructor of Inner private, but make Outer a friend of Inner. Note that not only the constructor but any private method of Inner can be called by Outer.
class Outer {
public:
class Inner {
friend class Outer; // <<---- friend
// private to Inner but also callable by Outer (because it's a friend):
Inner(int innerValue) : foo(innerValue) {};
public:
// (add public methods here)
int foo;
};
Outer(int innerValue) : _inner(innerValue) {};
const Inner& getInner() const {
return _inner;
};
private:
Inner _inner;
};
Solution 2 (access keys):
A different approach without friend but slightly more complex is to give the constructor a parameter which only Outer is able to construct (like a "key"). The constructor is then public, but other classes will not be able to call it since they can't provide the arguments required to do so:
class Outer {
// Our dummy struct which is only constructible by Outer:
struct ConstructInnerKey {
// Empty
};
public:
struct Inner {
Inner(int innerValue, Outer::ConstructInnerKey) : foo(innerValue) {};
// ^^^^^^^^^^^^^^^^^^^^^^^^
// a key is required (but not used)
// to construct an instance of Inner
// (add public methods here)
int foo;
};
Outer(int innerValue) : _inner(innerValue, Outer::ConstructInnerKey()) {};
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
// make a key and pass it to Inner
const Inner& getInner() const {
return _inner;
};
private:
Inner _inner;
};
Note that while this looks like it adds a performance overhead, this is not the case. Everything is optimized away and only serves for catching access violations during compilation as you'd like to.
Comparison:
Solution 2 has the advantage that Inner only grants Outer to access the constructor. So as long as you want to have "truly" private functions in Inner (not even accessible by Outer), this is a good solution. But solution 1 is a lot easier to write and understand (quick and dirty, so to speak).
Related
I have a class inside a class.
The outer class does some processing to generate an array of values.
I want the inner class to be able to access the outer class' array.
Is there a clean way to achieve this?
I'm thinking to have a method in the outer class that calls a method in the inner class sending him the address of the array and the inner class needs to hold a pointer in its private member section in order to later point to it by assignment from the method that receives the address. But this feels a little clunky.
Upon construction you can pass a reference of outer class to the constructor of the inner class. Using the reference you can call any function of the outer class.
// The actual definition of the inner class.
class inner {
public:
inner(outer& o) : outer_(o) // Set the reference.
{
}
// The function using the data in outer.
void do_stuff()
{
int x = outer_.get_data() + 5;
}
private:
// A reference to the outer class.
outer& outer_;
}
// The actual outer class.
class outer {
public:
outer() : inner_(*this) // Set the reference using the this object.
{
}
// This is the function you would like to call.
int get_data();
private:
inner inner_;
}
C++ has a concept of the nested class. A nested class, which is declared in another enclosing class. It is a member and has the same access rights as any other member of the enclosing class. But the members of an enclosing class have no special access to members of a nested class.you can refer to this sample code. Hope this will help
class Outer {
private:
int arry[];
class inner {
private:
int innerArr[];
void Fun(Outer *e) {
innerArr = e->arry;
}
};
};
int main(){
Outer out;
Outer::inner in;
in.Fun(out);
}
Okay, here it is in full. Key points:
C++ has nested classes, however that's a 100% compile-time thing dealing with scoping and encapsulation, the class instances are 100% independent.
Therefore if you want either class to use the other in any way, it must either create an instance or accept one.
(and then, given an outer instance, the inner class is allowed to access its private parts that's the only thing that actually differs from normal scoping).
So knowing that, here is a concrete example.
→ Outer owns a vector of Inners.
→ Inner needs to use its owning Outer instance
➥ say Outer could be some kind of List and Inner some kind of Item
class Outer
{
public: // can be private, in which case Inner won't be usable from outside
class Inner
{
Outer & m_outer;
public:
Inner(Outer & outer) : m_outer(outer) {}
void doOuterMagic() { m_outer.doMagic(); }
};
public:
void addInner() { m_inners.emplace_back(*this); }
private: // could be public, but I want to illustrate Inner access to private members
void doMagic() { std::cout <<"magic"; }
private:
std::vector<Inner> m_inners;
};
As with any class, you may also define it below the outer class if it's more readable. You'd do it like this:
class Outer
{
public: // can be private, in which case Inner won't be usable from outside
class Inner;
public:
// ... unchanged ...
};
class Outer::Inner // note the scoping here
{
// ... exactly what was in class Inner above
};
Notes:
Any relationship Outer and Inner have it up to your design, C++ assumes none.
If Outer works in close relationship with Inner, it's pretty common to have Outer create Inner instances and pass itself to them, as I did in addInner here.
I made m_outer a reference, but this prevents Inner from satisfying *Assignable requirements. If you need the class to satisfy those, make it a pointer instead.
I would like to declare an instance of my class outer, then use that to declare an instance of outer's child class inner. In the project I'm working on, I would like to be able to declare several instances of an inner class, using different constructors. These instantiations should be able to access the private variables in outer. This example is a simplification of my problem. Can someone tell me what I'm doing wrong, or post a working example?
using namespace std;
#include <iostream>
class outer
{
private:
int x;
public:
outer(int input){x=input;};
class inner
{
public:
int showx(){cout<<outinst->x<<"\n";};
};
};
int main()
{
cout<<"hello julian\n";
outer* clevername(5);
//I can't make it work past this point. The desired efect is
//to declare an instance of outer initiated with a value of x,
//use this instance of outer to declare an instance of inner,
//then use this instance of inner to return the original value of x
clevername->inner* ins;
cout<<ins->showx()<<"\n";
};
The nested class (inner) is not automatically a data member of outer nor does an object of type outer::inner have any access to any private members of any object of type outer. Moreover, to access members of an object you need the . operator. Finally, you're confusing objects with pointers.
Here is an attempt at a code that does perhaps what you intended (not tried it so it may still need debugging).
#include <iostream>
class outer
{
const int x;
public:
outer(int input) : x(input) {}
class inner;
friend class inner; // inner must be friend to access private member x
class inner
{
const outer* const outinst; // const pointer to an outer object
public:
inner(const outer*out) : outinst(out) {}
int showx() const
{ return outinst->x; }
};
};
int main()
{
std::cout<<"hello julian\n";
outer clevername(5); // declare object of type outer
outer::inner ins(&clevername); // declare object of type outer::inner
std::cout << ins.showx() << "\n";
};
Note that there is no benefit or other use of the fact that outer::inner is a member type of outer, i.e. the same effect could have been achieved (more easily) by declaring inner as another freestanding class.
This
clevername->inner* ins;
is wrong. Use
outer::inner ins;
instead. BTW you have also incorrect clevername declaration, it does not declare an object but a pointer. Do not use pointers unless you know what you are doing.
I have the code as below:
class outer {
public:
class inner {
outer & o;
public:
inner(outer & o): o(o) {}
};
inner i(*this);
};
But this gives me error saying:
error: expect specifier before token '*'
How can I do this? Do I have to use pointer?
1) Initialize i in outer's constructor's initializer list.
inner i;
outer(): i(*this) {}
2) (C++11 only) Use a brace-initializer for i. In this case you have to use braces, not parentheses.
inner i{*this};
You can't do it like this. You can do it in the constructor of the outer class
outer() : i(*this) {}
This is way is error prone though, since instance is not constructed yet and this is incomplete. Generally don't use this in initializer lists (gcc will give you a warning)
The other way is only valid in C++ 11
inner i { *this };
The member i can be declared in the class but it can't be initialized if you are using a compiler that supports C++98 only. You can initialize it in the implementation of the constructor of outer.
class outer {
public:
class inner {
outer & o;
public:
inner(outer & o): o(o) {}
};
outer() : i(*this) {}
inner i;
};
For a code like this:
class foo {
protected:
int a;
public:
class bar {
public:
int getA() {return a;} // ERROR
};
foo()
: a (p->param)
};
I get this error:
invalid use of non-static data member 'foo::a'
currently the variable a is initialized in the constructor of foo.
if I make it static, then it says:
error: 'int foo::a' is a static data member; it can only be initialized at its definition
However I want to pass a value to a in the constructor.
What is the solution then?
In C++, unlike (say) Java, an instance of a nested class doesn't intrinsically belong to any instance of the enclosing class. So bar::getA doesn't have any specific instance of foo whose a it can be returning. I'm guessing that what you want is something like:
class bar {
private:
foo * const owner;
public:
bar(foo & owner) : owner(&owner) { }
int getA() {return owner->a;}
};
But even for this you may have to make some changes, because in versions of C++ before C++11, unlike (again, say) Java, a nested class has no special access to its enclosing class, so it can't see the protected member a. This will depend on your compiler version. (Hat-tip to Ken Wayne VanderLinde for pointing out that C++11 has changed this.)
In C++, nested classes are not connected to any instance of the outer class. If you want bar to access non-static members of foo, then bar needs to have access to an instance of foo. Maybe something like:
class bar {
public:
int getA(foo & f ) {return foo.a;}
};
Or maybe
class bar {
private:
foo & f;
public:
bar(foo & g)
: f(g)
{
}
int getA() { return f.a; }
};
In any case, you need to explicitly make sure you have access to an instance of foo.
The nested class doesn't know about the outer class, and protected doesn't help. You'll have to pass some actual reference to objects of the nested class type. You could store a foo*, but perhaps a reference to the integer is enough:
class Outer
{
int n;
public:
class Inner
{
int & a;
public:
Inner(int & b) : a(b) { }
int & get() { return a; }
};
// ... for example:
Inner inn;
Outer() : inn(n) { }
};
Now you can instantiate inner classes like Inner i(n); and call i.get().
You try to access private member of one class from another. The fact that bar-class is declared within foo-class means that bar in visible only inside foo class, but that is still other class.
And what is p->param?
Actually, it isn't clear what do you want to do
Your Question is not clear but there is use case when you will get this issue .
Invalid use of non-static data member.
When you are using "non-static data member in another class try to not use with scope resolution operator
Example::className::memberData = assignivalue ;
instead of above try to use object of className class;
Example:: m_pClassName->memberData=assignValue;*
I have
class outer: public base
{
public:
class inner
{
foo();
}
}
How do i initialize these nested class?
Can I call foo() from the outer class?
Can you please tell me what is the thumb rule I should know while nesting class and accessing the members?
Thank you
I guess you're coming from java.
A c++ nested struct/class is like a java static nested type. It has no instance-relation with the containing type.
In fact you should be able to move the inner class to the containing namespace with no other changes than the potential need to mark the former inner class as a friend of the outer class.
See for demonstration http://ideone.com/ddjGX
How do i initialize these nested class?
You don't. You can only initialize members (class instances)
Can I call foo() from the outer class?
Not unless you are a friend or the method (foo()) is public
Can you please tell me what is the thumb rule I should know while nesting class and accessing the members?
I'd choose a nested type only if
the type is an implementation detail or depends on the outer class
the convenience of sharing static members (enums, typedefs, template arguments, static methods and fields) from the outer class: the inner class is implicitly a friend of the outer class.
I illustrated these 'rules of thumb' below. Note how the nested type has transparent access to private members of the outer class.
struct base {};
class outer: public base
{
private:
enum { some=42, special=67, implementation=999, details=-13 };
public:
struct inner
{
protected:
void foo() { int can_usethis = special + implementation + details; }
};
outer() : _inner() { }
void call_inner(inner& i) const
{
//i.foo(); // fails (protected)
}
void call_inner() const
{
//_inner.foo(); // fails (protected)
}
private:
inner _inner;
};
int main()
{
outer o;
outer::inner i;
// i.foo(); // fails: protected
o.call_inner(i);
}
You can instance inner object using scope operator :: (outer::inner()) . If you want to acceess foo() from outer class you maybe want to define outer like friend class of inner.