c++ reference to an inner class inside an outer class - c++

Just by curiosity, is it possible to declare a reference to an inner class in
an outer class :
class A{
private:
class B{
public:
B(double val):val_(val){}
private:
double val_;
};
public:
A(double val):b(B(val)){} /*problem*/
private:
B& b;
};
int main(){
A a(1.0);
}
It feels logic that it is impossible because I don't see how one can assign a
reference to a temporary variable. But I'd like to be sure. (I would like to
use a ref rather than a pointer to guarantee the presence of a B in A.)
Edit
As I had the question why I'd like to do that, here is my goal. Let's imagine
that the class B contains a lot of data and require a lot of memory. I don't
want to have many copy of B otherwise I will run out of memory. Now I have two
class C and D that both inherit of A. I want them to be related to the
same instance of B. I could do that with a pointer, but as said before I want
to make sure that at least a B exists somewhere, so I though that by using a
ref I would be able to guarentee that. I also would like B to be an inner
class so that I don't pollute my code. Thanks to your help, I now use a rvalue
reference and my code looks like this :
class A{
class B{
public:
B(double val):val_(val){}
private:
double val_;
};
public:
A(double val):b(B(val)){}
A(A const& a):b(a.b){}/*new problem*/
protected:
B&& b;
};
class C: public A{
public:
C(A const& a):A(a){}
};
class D: public A{
public:
D(A const& a):A(a){}
};
int main(){
A a(1.0);
C c(a);
D d(a);
}
but it doesn't compile.

No.
It'll compile if you use an rvalue reference:
class A
{
struct B {};
B&& b;
public:
A() : b(B()) {}
};
int main()
{
A a;
}
…but, annoyingly, this is a dangling reference by a special rule that prohibits the member b from extending the lifetime of that temporary B() as it otherwise might:
[C++11: 12.2/5]: [..] A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits. [..]
Now, if B were public, and if the B object were passed in from somewhere else, then you'd have achieved your goal:
struct A
{
struct B {};
B& b;
A(B& b) : b(b) {}
};
int main()
{
A::B b;
A a(b);
}
(live demo)
But, failing that, I don't see what else you can do to achieve this.
It would seem to be of limited utility, though; just have an actual B member!

If you want an object to be shared between copied member, use a std::shared_ptr.
It's the only standard way to guarantee your B object will persistently exist for all the A objects that use it.

Related

how to prevent usage of class members not yet constructed?

I have the following classes:
class A
{
public:
A() { x = 0; std::cout<<"A default ctor()\n"; }
A(int x_) { x = x_; std::cout<<"A normal ctor()\n"; }
int x;
};
class B
{
public:
B() { std::cout<<"B ctor()\n"; }
private:
std::string str;
};
and a function which creates an object B, taking an object A as parameter:
B
createB(const A& a) {
std::cout<<"a int: "<<a.x<<"\n";
return B();
}
if I design a class C, which has members of type A and B and constructs the B-object before A-object is constructed but using the A object to do so, this will compile without warnings but it will silently enter a bug:
class C
{
public:
C(): b(createB(a)), a(10) {}
private:
B b;
A a;
};
int main()
{
C c;
return 0;
}
Of course, the above example is a trivial one, but I've seen it in real world, in much more complex code (it's Friday, 8:30 PM and I just fixed this bug which led to segfaults).
How can I prevent this from happening?
I would agree with what others have suggested, namely that the onus is on the designer to ensure that objects are initialized before use. I see two ways of doing that in your case:
First (and easiest), reverse the order of a and b in the class definition:
class C
{
public:
C(): b(createB(a)), a(10) {}
private:
A a;
B b;
};
Second, you could move a to a base class if you want to really emphasize that it's initialization occurs before that of other members:
class CBase
{
protected:
CBase(): a(10) {}
protected:
A a;
};
class C : private CBase
{
public:
C(): b(createB(a)) {}
private:
B b;
};
I see three possible alternatives:
Require A to be constructed prior to constructing C:
class C
{
public:
C(const A& a) : a_(a), b_(a) {}
private:
A a_;
B b_;
};
Construct A prior to constructing 'B':
Delaying the construction of B until A is complete. This stops the undefined behavior from happening, but doesn't enforce proper behavior via the interface (as options 1 and 3 do)
class C
{
public:
C() : a_(/* construct as appropriate */)
{
b_.reset(new B(a_));
}
private:
A a_;
std::unique_ptr<B> b_;
};
If the design allows for it, have B contain (and expose) A.
This appears possible from the trivial example, but in real life may not be:
class B
{
public:
const A& my_a() {return a_;}
private:
// construct as appropriate (?)
A a_;
};
class C
{
private:
B b_;
};

mutually referential classes yield "incomplete type" error

I have a situation in which A has a reference to a class C defined inside B, and C has an instance of class B.
When I try to compile the code below, I get "field a has incomplete type". I assume this is because the compiler does not know how much memory it should allocate for an instance of A.
class A;
class B {
public:
class C {
A a;
};
};
class A {
A(const B::C& _c)
: c(_c)
{}
const B::C& c;
};
But when I try to compile this, I get "C in class B does not name a type":
class B;
class B::C;
class A {
A(const B::C& _c)
: c(_c)
{}
const B::C& c;
};
class B {
public:
class C {
A a;
};
};
How can I convince the compiler that B::C is a real type?
As an absolute guess, I notice there's one permutation you haven't tried:
class B {
public:
class C; // Forward declaration
};
class A {
A(const B::C& _c)
: c(_c)
{}
const B::C& c;
};
class B::C {
A a;
C() : a(*this) {} // Thanks Nim for pointing this out!
};
This is quite possibly illegal, but worth a shot I think. If it doesn't work, then I don't see any way around the problem.
The forward declaration for A doesn't serve a purpose: you can't declare an instance of an incomplete type.
As to B::C, I don't think you can use nested names in an incomplete type. Just don't nest C in B: as far as I know this doesn't give you any significant advantages* and stops you from forward declaring it.
*The only advantage I can think of is that you can define it in the private section, but then A would have no business with it in the first place.

Why protected superclass member cannot be accessed in a subclass function when passed as an argument?

I get a compile error, which I'm slightly confused about. This is on VS2003.
error C2248: 'A::y' : cannot access protected member declared in class 'A'
class A
{
public:
A() : x(0), y(0) {}
protected:
int x;
int y;
};
class B : public A
{
public:
B() : A(), z(0) {}
B(const A& item) : A(), z(1) { x = item.y;}
private:
int z;
};
The problem is with x = item.y;
The access is specified as protected. Why doesn't the constructor of class B have access to A::y?
It's because of this:
class base_class
{
protected:
virtual void foo() { std::cout << "base::foo()" << std::endl; }
};
class A : public base_class
{
protected:
virtual void foo() { std::cout << "A::foo()" << std::endl; }
};
class B : public base_class
{
protected:
virtual void foo() { std::cout << "B::foo()" << std::endl; }
public:
void bar(base_class *b) { b->foo(); }
};
If that were legal, you could do this:
A a;
B b;
b.bar(&a);
And you'd be calling a protected member of A from B, which isn't allowed.
The other answers explain the reasoning behind preventing your B object from accessing the protected parts of A in your example, even though B 'is-a' A. Of course, the easiest way to fix this problem is to make the parts of A you want access topublic` or have publicly accessible accessor methods.
However you might decide that's inappropriate (or you might not have control over the definition of A). Here are some suggestions to let you work around the problem, in increasing order of subverting A's access control. Note that all of these workarounds assume that class A is copy-constructable.
In the first case, you simply use the copy constructor for A to set up an initial state for that part of the B object, then fix it up afterward:
class B1 : public A
{
public:
B1() : A(), z(0) {}
B1(const A& item) : A(item), z(1) {
// fix up the A sub-object that was copy constructed
// not quite the way we wanted
x = y;
y = 0;
}
private:
int z;
};
I find that incredibly confusing and probably very error prone (assuming that we want the A sub-object in the B object to be different than the A object being passed to the constructor - an unusual situation, but it's what was given in the problem). However, the fact that it can be done gives some justification for the more subversive examples that follow...
The next example creates a temporary B object that has an exact duplicate of the A object we want access to. We can then use the temporary B object to get to the items that were protected:
class B2 : public A
{
public:
B2() : A(), z(0) {}
B2(const A& item) : A(), z(1) {
// create a special-use B2 object that can get to the
// parts of the A object we want access to
B2 tmp( item, internal_use_only);
x = tmp.y; // OK since tmp is of type B
}
private:
int z;
// create a type that only B2 can use as a
// 'marker' to call a special constructor
// whose only purpose in life is to create
// a B object with an exact copy of another
// A sub-object in it
enum internal_use {
internal_use_only
};
B2( const A& item, internal_use marker) : A(item), z(0) {};
};
I find that solution to be a bit less confusing than the first, but it's still confusing (in my opinion). Having a bastard version of of B object just to get to the parts of the A object we want is odd.
We can do something about that by creating a special proxy for A objects that gives the access we want. Note that this is the 'most subversive' workaround because it's something that any class could do to get to protected parts of A, even if they aren't sub-classes of A themselves. In the case of the B class, there's some legitimacy to getting to the protected parts of A objects, since B is-a A, and as we've already seen there are workarounds that let us get access that use only rights that class B already has, so I consider this a cleaner version of those workarounds in class B's case.
class B3 : public A
{
public:
B3() : A(), z(0) {}
B3(const A& item) : A(), z(1) {
// a special proxy for A objects that lets us
// get to the parts of A we're interested in
A_proxy tmp( item);
x = tmp.get_y();
}
private:
int z;
class A_proxy : public A
{
public:
A_proxy( const A& other) : A(other) {};
int get_x() {return x;};
int get_y() {return y;};
};
};
IBM's documentation summarizes it best:
A protected nonstatic base class
member can be accessed by members and
friends of any classes derived from
that base class by using one of the
following:
A pointer to a directly or indirectly derived class
A reference to a directly or indirectly derived class
An object of a directly or indirectly derived class
Thus, using your example above as the basis:
B::B(const A& item) : A(), z(1) {
// NOT OK because `item` is not a reference to the derived class B
//int i = item.y;
// OK because `item` reinterpreted as a reference to the derived class B
// Do not do this (bad!) -- for illustrative purposes only
int i = reinterpret_cast< const B& >(item).y;
// OK because it is equivalent to `this->x = i`,
// where `this` is a pointer to the derived class B
x = i;
}

C++ referring to an object being constructed

In C++ I have a reference to an object that wants to point back to its owner, but I can't set the pointer during the containing class' construction because its not done constructing. So I'm trying to do something like this:
class A {
public:
A() : b(this) {}
private:
B b;
};
class B {
public:
B(A* _a) : a(_a) {}
private:
A* a;
};
Is there a way to ensure B always gets initialized with an A* without A holding a pointer to B?
Thanks
Try this:
class A;
class B {
public:
B(A *_a) : a(_a) {};
private:
A* a;
};
class A {
public:
A() : b(this) {};
private:
B b;
};
Since B is contained completely in A, it must be declared first. It needs a pointer to A, so you have to forward-declare A before you declare B.
This code compiles under more-or-less current versions of g++.
In C++ I have a reference to an object that wants to point back to its owner, but I can't set the pointer during the containing class' construction because its not done constructing.
You can store the pointer alright.
What you can't do is to try to get to the members/methods of A through the pointer in the constructor of B, since the parent instance might not be fully initialized at the point:
#include <iostream>
class Y;
class X
{
Y* y;
public:
X(Y* y);
};
class Y
{
X x;
int n;
public:
Y(): x(this), n(42) {}
int get_n() const { return n; }
};
X::X(Y* p): y(p)
{
//Now this is illegal:
//as it is, the n member has not been initialized yet for parent
//and hence get_n will return garbage
std::cout << p->get_n() << '\n';
}
int main()
{
Y y;
}
If you were to switch around the members in Y, so n would get initialized first, the constructor of X would print 42, but that is too fragile to depend on.

Circular reference in C++ without pointers

Is there a way to define circular references without using pointers?
I need to have somthing like this:
struct A;
struct B {
A a;
};
struct A {
B b;
};
Thanks!
You can use references instead
struct A;
struct B {
A& a;
};
struct A {
B b;
};
But no it's not possible to create a circular reference without some level of indirection. What your sample is doing is not even creating a circular reference, it's attempting to create a recursive definition. The result would be a structure of infinite size and hence not legal.
No, there's not. Such structure would have infinite size.
You can use smart pointers (shared_ptr and weak_ptr) to avoid direct pointer manipulation, but that's about it.
How could this work? If I remember correctly, the address value of a reference can't be modified once set, so you can't define a circular reference.
It could work like the following (same as Jared's example plus constructors defined):
struct A;
struct B {
A& m_a;
B(A& a) : m_a(a) {}
};
struct A {
B m_b;
//construct B m_b member using a reference to self
A() : m_b(*this) {}
//construct B m_b member using a reference to other
A(A& other) : m_b(other) {}
};
In C++, T o means "an object of type T, not a reference to some T (as, for example, with reference types in C# and Java). With the code from your question, type A would have a sub object of type B (named b), and that B in turn would have a sub object of type A (named a). Now, that a would in turn have another A inside (again called a), which then has another B, which...
No, this will not work.
What you probably want is that an A referres to a B, which in turn referres that A. This can be done using pointers:
struct A;
struct B {
A* a;
B(A*);
};
struct A {
B* b;
A(B* b_) : b(b_) { if(b) b.a = this; }
};
B::B(A* a_) : : a(a_) { if(a) a.b = this; }
I don't think it can be done using references.
ChrisW's solution can be generalized a bit like this :
template <class defaultState> struct Context;
struct State1 {
Context<State1>& mContext;
State1(Context<State1> & ref) : mContext(ref) {}
};
template <class TDefaultState>
struct Context {
TDefaultState mState;
Context() : mState(*this) {}
};
This now allows you to do
Context<State1> demo;
Further, State can have some template helper code as well
template <class State>
struct TState {
typedef Context<State> TContext;
typedef TState<State> TBase;
Context<State> & mContext;
TState(Context<State> &ref) : mContext(ref) {}
};
struct State2 : TState<State2> {
State2(TContext & ref) : TBase(ref) {}
};
struct State3 : TState<State3> {
State3(TContext & ref) : TBase(ref) {}
};
Which now allows you to do any of
Context<State2> demo2;
Context<State3> demo3;