Er, okay.
I have two classes: A and B.
Class B must container a member which is a class A object. Class A must contain a member that's a class B object.
How do I declare these so that I don't get errors?
Printable View
Er, okay.
I have two classes: A and B.
Class B must container a member which is a class A object. Class A must contain a member that's a class B object.
How do I declare these so that I don't get errors?
I'll give you some hints:
forward declarations
OR
change where the #include statements are placed
Eh, what's a forward declartion? Is that just a class name; thing? I tried doing that and i think I got an error, but...
Show us what you did. Also, think about the logic behind having a circular dependence like that, and what it means (hint: it comes out bad). Use a pointer or reference to one (or both) of the objects if possible, instead of actual instances.
Zack L. could you give an example of doing this? TIA
As Zach pointed out, this leads to infinite dependence, or whatever you call it.
Class A's constructor constructs an object of class B. But class B's constructor constructs an object of class A. Therefore, you'll get an infinite number of objects of class A and B being constructed.
>>could you give an example of doing this?
Very simply, instead of:
You can have it hold pointers to each other:Code:class B; //forward declaration
class A
{
public:
//...
protected:
B member; //holds a B, which...
};
class B
{
public:
//...
protected:
A member; //holds an A, which... (see above)
};
That's an example of one thing you can do, though without further information I have no idea exactly what the original poster's intention was in having each contain an object of the other.Code:class B; //forward declaration
class A
{
public:
A() :member(this) {} //Pass a pointer to myself when constructing B
protected:
B member; //Holds a B, which...
};
class B
{
public:
B(A* parent) :member_parent(parent) {}
protected:
A* member_parent; //Holds a pointer to the A that it belongs to
};
Once I have multiple objects created, I need to be pick and object and then grab a specific material for it. Lets say I grab the steelBall and need to get the info from the mat class for the steel material or glassCup and need to grab the glass material from the mat class. The way i am trying to do this is in the obj class have a variable, matID, and compare it to the matID in the mat class. Hope i explained this well enough.
Code:#include <math.h>
#include <vector>
#include <iostream>
#include <string>
using namespace std;
const double gravity = 9.8;
//Object Class
class obj
{
public:
string objName;
double matID;
double objMass;
bool objRoll;
};
class mat
{
public:
double matID;
double objWeight;
double objDensity;
}
int main()
{
obj steelBall, glassCup;
mat steel, glass;
steelBall.matID = 0;
steelBall.mass = 5;
steel.matID = 0;
steel.weight = 3;
steel.density = 5;
glassCup.matID = 1;
glassCup.mass = 3;
glass.matID = 1;
glass.weight = 2;
glass.density = 2;
return 0;
}//end main()
Better yet, you can use pointers:
That saves you the trouble of trying to match up ID's every time you want to calculate something using information from the material.Code:class mat; //forward declaration
class obj
{
public:
string objName;
mat* material;
double objMass;
bool objRoll;
};
...
obj steelBall, glassCup;
mat steel, glass;
steelBall.material = &steel; //material now points to steel
steelBall.mass = 5;
steel.matID = 0;
steel.weight = 3;
steel.density = 5;
...
std::cout << "The density of the Steel Ball is " << steelBall.material->density << "." << std::endl;
Thank you so much for the help. :) Hope this helps the person who orginally started this post. :)
In Hunter2's example, a reference would work as well (this is a personal preference, but in this case, it is the solution that I would prefer).
In either case (pointer or reference), you have to make sure that your material object does not go out of scope at any point. (If you just used an object, it would simply be copied -- make sure appropriate copy ctor and operator= is defined.)
One type of solution would be to make a singleton class, a 'MaterialRegistry'. Essentially, it would allow you to construct a material object, and key it to, say, a specific name. Then, if you want steel, you ask the registry object for the material data for 'steel', and if it has the data, it gives it to you. If it didn't, you could deal with it as you saw fit.
What this solution allows you to do is to avoid replicating data for a specific material, which avoids the necessity of hard-coding (or even reading in) data in multiple places throughout your code.
Here is a reference I found on design patterns: http://home.earthlink.net/~huston2/dp/patterns.html
I haven't thoroughly checked over the site, but it looks fairly decent. They have the singleton pattern on there, and looking at the other 'Creational Patterns' probably give you a decent idea about where I was headed with the idea of a registry.
Anyway, if you are interested in OO design like this, I also recommend the Design Patterns book.
Hm. I'm going to assume that the constructor does something important, because just having something like A *member_parent gives me a "syntax error before *" message. What exactly IS the :member syntax after the function prototype anyway? I've never seen that before. What does it do?Code:class B
{
public:
B(A* parent) :member_parent(parent) {}
protected:
A* member_parent; //Holds a pointer to the A that it belongs to
};
You need a forward declaration of A:
Code:class A;
class B
{
public:
B(A* parent) :member_parent(parent) {}
protected:
A* member_parent; //Holds a pointer to the A that it belongs to
};
>>What exactly IS the :member syntax after the function prototype anyway?
When a class contains member variables, and an instance of the class is created (an object of the class), all of its member variables must also be created - and if one of the member variables is an object of another class, it must be constructed. :member(something) simply tells the constructor that when constructing 'member', you should pass (something) to its constructor. So:
B(A* parent) :member_parent(parent) {}
The constructor of B takes an A*, and we'll name it 'parent'. Now, when B's constructor is called, i.e. it's being constructed, it will construct member_parent which is an A* by passing the A* constructor 'parent'. Since a pointer is a POD type, the 'constructor' of A* is automatically created, and all it does is copy the value passed to it into itself. So what happens is the value stored in 'parent' is copied into member_parent when B's constructor is called.
Another example:
So in A's constructor, bObject is constructed by passing the values 5 and 6 to its constructor, and bObject2 is constructed by passing the values 1 and 2 to its constructor.Code:class B
{
public:
B(int arg1, int arg2)
{
x = arg1;
y = arg2;
}
protected:
int x;
int y;
};
class A
{
public:
A() :bObject(5, 6), bObject2(1, 2)
{
}
protected:
B bObject;
B bObject2;
};
Dev-C++ isn't letting me do forward declarations. Do I need to put them somewhere special?
Well, what errors are you getting? And what's your code?
Ah, nevermind. It had to do with the way I was doing the function. I'm not sure what I was doing but obviously it was wrong and I am a VERY BAD BOY.
Anyway though, sort of derailing this, how do I compile/create a multi-source project, again?
Mm, well, what compiler/IDE/whatever are you using? In MSVC you just add a new .cpp file to your project and a .h file to put your function prototypes in, include the .h file in main.cpp, and it will all be built together.
Dev-C++... Look a few posts back. ;)
Anyway, you can make projects in Dev, and do essentially the same thing as MSVC.
Another way, compile (do not build) all of your source files individually, and then build the project (this will link the object files). I don't use Dev (or Windows for that matter) anymore, so I can't give you much more than that.
It's called an "initializer list". The following is a simple example.Quote:
Originally Posted by Hunter2
No initializer list, simple assignment within constructor body:
Initializer list:Code:class A
{
public:
A(int i1, int i2, int i3)
{
a = i1;
b = i2;
c = i3;
}
int get_a()
{
return a;
}
private:
int a;
int b;
int c;
};
The code:Code:class A
{
public:
A(int i1, int i2, int i3): a(i1), b(i2), c(i3)
{
}
int get_a()
{
return a;
}
private:
int a;
int b;
int c;
};
: a(i1), b(i2), c(i3)
says to set a equal to i1, set b equal to i2, and set c equal to i3.
Initializer lists can be more efficient because they initialize the member as it's being created, rather than creating the member and then performing an assignment, and in some cases an initializer list is the only way to set values for certain types of members.
>>No initializer list, simple assignment within constructor body:
Yes, for POD types. But if you have a class with no copy constructor or = operator defined, or no default constructor either, then you MUST do the initialization in the initializer list.
See above:Quote:
>>No initializer list, simple assignment within constructor body:
Yes, for POD types. But if you have a class with no copy constructor or = operator defined, or no default constructor either, then you MUST do the initialization in the initializer list.
Does the code I posted produce errors? I wonder if you got half of your 2,000 posts with responses like that? In addition, you might want to try to learn to speak to your audience.Quote:
...and in some cases an initializer list is the only way to set values for certain types of members.
Also, the initializer list is the proper place to call base class ctors.Quote:
Originally Posted by Hunter2
Dev-C++ doesn't handle projects right for some reason. It doesn't recognize any changes I make to the included headers and whatnot. Yes, I AM saving them between compiles. I'm thinking it's not making new objects (Is that what you get from the first compile stage?) and just tossing in the old ones or something.
>>and in some cases an initializer list is the only way to set values for certain types of members.
Didn't see that.
>>Does the code I posted produce errors?
No, but the object of my post was to point out that even though the results may be the same, using the initializer list is in no way equivalent to an assignment.
>>I wonder if you got half of your 2,000 posts with responses like that?
Practice what you preach. Your own post is little more than a restatement of my previous post, and less accurate and in-depth at that.
>>In addition, you might want to try to learn to speak to your audience.
My posts are for everybody to see; I simply added to (clarified?) your post. On the other hand, you've just contradicted yourself by dedicating an entire post to 'defending' yourself and insulting me, even though I did nothing deserving of your flames.
Where did you say that? Here is your entire post:Quote:
Originally Posted by Hunter2
You never even used the word "assignment". Once again, compare that to what I posted:Quote:
>>No initializer list, simple assignment within constructor body:
Yes, for POD types. But if you have a class with no copy constructor or = operator defined, or no default constructor either, then you MUST do the initialization in the initializer list.
====Quote:
Initializer lists can be more efficient because they initialize the member as it's being created, rather than creating the member and then performing an assignment, and in some cases an initializer list is the only way to set values for certain types of members.
I didn't notice where you identified the code as an initializer list, nor explained in simple terms what it does. This is what I saw:Quote:
Originally Posted by Hunter2
----Quote:
The constructor of B takes an A*, and we'll name it 'parent'. Now, when B's constructor is called, i.e. it's being constructed, it will construct member_parent which is an A* by passing the A* constructor 'parent'. Since a pointer is a POD type, the 'constructor' of A* is automatically created, and all it does is copy the value passed to it into itself. So what happens is the value stored in 'parent' is copied into member_parent when B's constructor is called.
If you are having trouble with porjects (from my past experience, it handles them well, but I don't have Windows to use it on, so I can't directly help you troubleshoot), then you can compile then individually. Simply compile -- but do not build -- all of your source files. Then build the project. Assuming they are all in the same directory, you should not have problems. If you think it is not properly recreating your object files, simply go into the folder, delete them, and then perform your compilations, making sure you are compiling the correct copy of the source files.Quote:
Originally Posted by suzakugaiden
Cheers
>>I didn't notice where you identified the code as an initializer list
I did not identify it as an initializer list very simply because I did not know the correct terminology; I did not dispute that you added this information to the discussion. Because I realized that my explanation was somewhat confusing and difficult to follow, I added a code example that hopefully explained better; and above all, my information was accurate.
>>rather than creating the member and then performing an assignment
True, but the first 95% of your post seems to equate the initializer list with assignment, and only in the last line do you vaguely suggest that there is a difference - and then instead of stressing the greater significance of the distinction, all you say is that there is a performance gain due to the fact that the value is given during creation rather than the object being created and then assigned a value later!
>>You never even used the word "assignment".
I'd assumed that my comment would prompt further investigation into the matter, and the repeated use of 'constructor' would link back to my own explanation where I explained exactly what initializer lists do and how - and therefore the distinction would be made, albeit somewhat indirectly.