How do I handle classes that reference each other? [closed] - c++

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Here's the code:
class B
{
A a;
};
class A
{
B b;
};
int main()
{
return 0;
}
Here's the error:
1>c:\mine\visual studio 2010 projects\myproj\compiled equivalent.cpp(7):
error C2079: 'B::a' uses undefined class 'A'

You can't. Two classes cannot contain each other as members. Consider answering the question “What is the size of the type A?” Well A contains a B, so what is the size of B? Well B contains an A, so what is the size of A? Oh dear, we have an infinite loop. How would we possibly store this object in finite memory?
Perhaps a more appropriate structure would be to have one of the classes contain a pointer to the other type. The type that is pointed to can simply be forward declared before the pointer member is declared:
class A; // A is only declared here, so it is an incomplete type
class B
{
A* a; // Here it is okay for A to be an incomplete type
};
class A
{
B b;
};
Now the type B doesn't contain an A, it just contains a pointer to an A. There doesn't even have to be an A object for it to point to, so we've broken the infinite cycle.

Considering you ask for references between the classes, probably you come from Java, C# or similar background where one can only put references to objects inside other objects.
In C++ there is no such restriction: you are allowed to have one object's content completely nested inside another one. But for this to work you must provide the definition of the nested object beforehand. C++ needs this definition in order to compute the size and layout of the outer object. In order to escape from this nesting you need to place not the object itself but a pointer or reference to it inside the outer object.
That being said,
// C#
class A
{
int x;
B b;
}
class B
{
int y;
A a;
}
becomes
// C++
class B; // tell the compiler that B is a class name
class A
{
int x;
B *pb; // the forward declaration above allows you to declare pointer to B here
};
class B
{
int y;
A *pa;
};
if you decide to use the pointer syntax.
What this allows is to have things like:
// C++ again
class C
{
A a;
B b;
A *pa2;
};
which has memory layout in the form of:
C:
a.xa.pb
b.yb.pa
pa2
which is not possible in Java/C#.

Related

Is it possible to make a property of type class A, inside of class A? [duplicate]

This question already has answers here:
Why structure can not contain Instance of itself? [duplicate]
(7 answers)
Closed 5 years ago.
So lets say that I have a class named A. Class A has several basic properties, however one of it's properties is supposed to be of type Class A. Here is an example of what I am talking about:
class A {
public:
int a;
bool b;
A c;
};
However, when I try to build this, I get the error "incomplete type is not allowed", which I am assuming has to do with the fact that property c does not have a definition for A yet, but even if I put:
class A;
before I construct class A, however I still get the error "incomplete type is not allowed". If anyone knows how to create a property of type class A inside of class A, I would appreciate your help.
Thanks
Edit: I do not believe this post is a duplicate because I am trying to find out How you can create a property of type class A inside class A, instead of simply "why you can't create an instance of itself..."
Yeah this is not possible, you have to declare it as a pointer like so:
class A {
public:
int a;
bool b;
A* c;
};
Then you can just allocate c on the heap.
The reason is that the compiler cannot know the size of A. Think like a compiler. Could you figure out the size of A? Well maybe 4 bytes for member a. Then maybe a byte for b. And for c, we have to look inside the class definition of A. Well the size of A is therefore 4 bytes for member...
You see where this is going to?
As far as I know you need complete types to define data members by value because they are allocated directly within each class object and this is important to know the class object size. The forward declaration doesn't help here because it only provides an incomplete type. You can have a reference or pointer to A, for example:
class A {
public:
int a;
bool b;
A* c;
};

Can I change the type of an object at runtime in C++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have 2 objects in my C++ program, both extending from the same parent class:
class A, and class B, both extending class base.
Is it possible create an object using class A, and then change it later in the program to class B?
Short answer, no. You cannot safely cast from A to B or B to A. You can safely cast to the base class since A IS_A base class and B IS_A base class but A and not a B and vice versa. There is no portable or safe way to do this. Whilst your compiler might let you do it and whilst it might appear to work the result of casting between to unrelated classes in this manner is undefined.
Incidentally, there is no reason why you can't add a cast constructor to allow A to be constructed from B and vice versa. That would be perfectly safe. You would just use the members of A to initialise the members of B and vice versa. Any members that are not common you'd have to deal with, probably be assigning them default values.
The following code works:
#include <iostream>
class Base {};
struct A : public Base {int a;};
struct B : public Base {int b;};
int main()
{
A *a = new A();
a->a = 1;
B *b = reinterpret_cast<B *>(a);
std::cout << b->b << std::endl;
return 0;
}
This is extremely ugly though and won't work properly if A and B don't have the exact same memory layout. This works if you need a and b to be the same object. If you don't mind them being different objects and residing in different places in memory then you can just write a constructor in B that receives an object of type A or a conversion operator.
This sounds like a classic example of the XY Problem and there probably exists a much more elegant solution to your actual problem.
As others have mentioned, no you cannot do this...technically. You can in fact achieve this effect through convert constructors and virtual functions.
If you write a convert constructor from A to B and B to A:
A::A(B convertFrom); // Convert from B to A
B::B(A convertFrom); // Convert from A to B
And you make the essential parts of each class virtual:
class base
{
virutal void baseClassFunction();
};
class A
{
virtual void baseClassFunction()
{
// Do things for A
}
};
Class B
{
virtual void baseClassFunction()
{
// Do things for B
}
}
Then you can simply make a pointer of type base which can hold a reference to either A or B.
Example bringing it all together;
int main()
{
base *ptr = new A();
bool needs_to_be_B;
...
// Program logic
ptr->baseClassFunction();
...
if(needs_to_be_B)
{
base *tmp = new B(*ptr);
delete ptr;
ptr = tmp;
delete tmp;
}
// ptr is now a B
ptr->baseClassFunction();
}
If you are confused look up virtual functions and convert constructors.

How can I create two different classes that have references to eachother within their code? [duplicate]

This question already has answers here:
Two classes that refer to each other
(2 answers)
Closed 8 years ago.
How can I create two different classes that have references to eachother within their code in C++?
It would look something like this;
class A
{
B b;
}
class B
{
A a;
}
I get an error on the line of the
B b;
within class A stating;
error: 'B' was not declared in this scope
Rest easy in that I am not declaring a
B b = new B;
in A, nor am I declaring a
A a = new A;
in B, as I'm aware it would cause a StackOverflowException. I will use getters and setters to manipulate the data.
Use forward declarations, and make the members pointers. It's easiest with two different headers, although it could be done in one:
// A.h
class B;
class A
{
B* m_pB;
};
And:
// B.h
class A;
class B
{
A* m_pA;
};
Then #include both headers in each .cpp file (A.cpp and B.cpp).
This is probably what you want:
class B;
class A
{
B* b;
}
class B
{
A* a;
}
Note that the class B is forward-declared as a class so that the compiler knows what it is when defining A. Also note that A::b is a pointer to B and B::a is a pointer to A (what you probably mean by "reference" if you come from a Java background). If A::b was declared to be of type B and B::a was declared to be of type A then each A object would literally contain an entire B object inside it and vice versa, which I'm guessing is not what you wanted (and is obviously impossible anyway).

Invoking method in C++ [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
A question about C++ programming.
Can you do in C++ something like this:
Lecture le;
Carriage ca = le;
No casting, just writing like that. The problem is, when I am trying to invoke a method which belongs to Lecture class the methods is underlined in red.
ca.runIt();
I am not quite sure if I understood the specification of my task, but there is given this snippet of code. Best regards
Can you do in C++ something like this:
Yes.
struct Lecture {
};
struct Carriage {
Carriage(const Lecture&) {
}
void runIt() {
}
};
int main() {
Lecture le;
Carriage ca = le;
ca.runIt();
}
The problem is, when I am trying to invoke a method which belongs to Lecture class the methods is underlined in red.
Of course. ca isn't a Lecture. ca is a Carriage. You can only invoke Carriage methods on ca.
Let's break it down, from the general case to the most specific.
If you have some arbitrary class A and some other arbitrary class B, the statement:
A a;
B b = a;
is generally not going to work. It will certainly not work by itself; you have to put effort into making it work.
So now, let's get specific. If B is a class derived from A, then it will also not work. If A is derived from B, it will still not work.
Why? Because A a defines an object, not a reference. It creates a value. B b = a; is an attempt to store the value a into a new value b. You cannot do that.
If A is derived from B (B is the base class), you can do this:
A a;
B &b = a;
That's legal C++, and it's meaningful too. b now refers to part of a. Specifically, the part of a that is the base class.
Note that the reverse does not work. If A were the base class, C++ would raise an error.
Now, there is one way to make the general statement work.
A a;
B b = a;
If you want this to be reasonable for a specific class B, then B must be defined as follows:
class B ... //Whatever base classes you want.
{
public:
B(const A &a);
};
The constructor that takes a const A & is a conversion constructor. It's job is to create a B object using data from an a object. Because this conversion constructor was declared without the explicit keyword, then it can be used for implicit conversions like B b = a; If it were declared with the explicit keyword, you would have to explicitly convert it: B b = B(a);.
Having a conversion constructor on a class means that any instance of A can be converted into a B. So you can pass A to a function that takes a B (either by value or by const&. Not by reference) without having to do an explicit conversion.
Note that conversion constructing an object does not allow you to call functions from A on the object B. You can only call functions on B which B defines or are defined by one of B's base classes.

Right way to instantiate instance-variables in C++ [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I want to ask where in C++ is the right place to instantiate a instance-variables? I think it should not be in the class declaration, but otherwise I don`t see any disadvantages apart from poor object-oriented design:
class A{ member m; };
I think it should better be like:
class A{ extern member m; };
But I don`t know how to realize it without a pointer like this:
class A{ member* m };
A::A(){ m = new member; }
Is there a "clean solution" to realize this on the stack (without using pointers)?
You can use the constructor initialization list to construct all your member variables as you need.
A::A(const member& memberArg)
: m(memberArg)
{ }
Look at this for more info.
I think you have a misunderstanding of how objects are instantiated. If all you do is declare a class, no member variables are actually instantiated. It isn't until you construct an instance of that class that its member variables exist.
Here's an example to show when a member object gets instantiated:
class ClassA
{
public:
ClassA() { std::cout << "Hello!\n"; }
};
class ClassB
{
public:
ClassA objA;
};
int main()
{
// do some work
ClassB objB; // here, a ClassB object is created, and with it its member ClassA object, so "Hello!" is printed
return 0;
}
As to exactly how you specify what kind of ClassA object to create if its constructor requires arguments, the other answers do a fine job explaining it.
I think it should not be in the class declaration, but otherwise I don`t see any disadvantages apart from poor object-oriented design:
class A{ member m; };
What in your mind makes this poor OO design? This is the preferred mechanism in C++.
I think it should better be like:
class A{ extern member m; };
This isn't valid code. Qualifying member data with a storage class specification such as extern is illegal.
But I don`t know how to realize it without a pointer like this:
class A{ member* m; };
A::A(){ m = new member; }
That will work, but why do that? It looks to me like you are trying to import a Java POV into C++. Everything is allocated, and everything is a reference in Java. In many (most!) cases there is no reason to allocate data members in C++. All it does is add an unneeded indirection and add a place where memory can leak.
You want to use member initializers: they are the only way to initialize class members that have a constructor that requires parameters, and the cleanest way to initialize other class members.
If you have class A and a member m with a constructor:
class A { member m; }
You want
class A { member m; A(); }
A::A()
: m(<constructor params>)
{
}
You would declare your instance variables in your .h file:
A.h
class A {
public:
A();
private:
int value;
double someOtherValue;
}
You can instantiate them in your .cpp file like so:
A.cpp
A::A(): value(5), someOtherValue(10.0)
{
...
}
If the member object is to be totally controlled by the enclosing A object, your first example is the proper way to do it. It does have the downside of requiring a complete definition of member at the point where A is defined.
You could check out the pimpl idiom to reduce coupling, but that still requires the object to be heap-based and not stack-based.