Sign in to follow this  

C++ Header Files

This topic is 2848 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello. I've been declaring my functions and primitives in my C++ Header files but it seems that I can't declare objects in advance. What's up with this, how should I do this? Here's an example of what I'm trying to do.
//Circle.h
class Circle
{
private:
	double radius;
	//So here's where I thought I would declare objects without constructing them, apparently not though
	Apple myApple;

public:
	Circle();
	~Circle();
	double getRadius();
};

Share this post


Link to post
Share on other sites
An object is constructed when you declare it, even if it is in the header.

If all you want is a placeholder for an object in your class, make the member a pointer: Apple* myApple

Share this post


Link to post
Share on other sites
what you did there is perfectly fine.
however, you have to include the definition of your Apple class before
declaring an instance of Apple.

You can get around this with forward-defining class apple and putting a pointer to Apple in your Circle class.



class Apple;

class Circle {
private:
Apple* mApple;
};

Share this post


Link to post
Share on other sites
I don't really need placeholders, I'm just confused coming from Java. I have another question then. If I construct objects in a class' constructor, aren't they going to go out of scope as soon as the constructor is done executing? Does this mean I should declare all my objects on the heap and manage them myself?

Share this post


Link to post
Share on other sites
What's the error that you get?

When you say that a Circle contains and Apple (btw, WTF?), the compiler has to know, at that instant, what an Apple is). That typically means that you need to '#include "apple.h"' from circle.h. But don't just write that; you must understand how this stuff works in detail, or you will cause yourself worlds of pain.

So, read this.

If that fixed it, great!

If you already know that part, and you're getting an error more like


In constructor 'Circle::Circle()':
error: no matching function for call to 'Apple::Apple()'
note: candidates are: ...


, though, then you need to keep reading beyond the horizontal line.




When you don't define any constructors for a C++ class, the compiler provides two for you. One of these is a default copy constructor. This defines how to take one instance as a parameter to the constructor (by const reference), and construct another one which is a "copy". (It does this in a very dumb way, so sometimes you have to write one yourself to replace this default).

The other is a default no-argument constructor, often just called "the default constructor". (Although sometimes that term is used to mean a constructor that can take no arguments, even though it's one that you wrote.)

If you write a copy constructor, the default copy constructor doesn't get generated, of course (since it would conflict). But here's the tricky part: if you write any constructor at all, the default no-argument constructor also doesn't get generated.

This means that you can create a class such that every constructor takes an argument. This is often exactly what you want to do: some classes don't have a sensible "default" value, so it would be wrong to give them a no-argument constructor.

Still with me?

Now, when you store instances of other classes within a class, such as your Circle (which is defined to include an Apple in its data), every constructor for that containing class will have to initialize the contained instance. This also applies to base classes; i.e. you'd have the same problem if you inherited Circle from Apple.

Now comes another tricky part: when you call a constructor - any constructor, whether you wrote it yourself or not - the initialization I'm talking about happens before the actual code in the body of the constructor. Each member and base has a constructor called (well, except for members that are 'int's or other primitive types) to create the 'parts', and then the constructor body is used for any extra work that needs to be done to make the parts into a 'whole'.

So, which constructor is called on the members and bases? Well, by default, the default (i.e., no-argument) constructor is called. Which makes sense; that's why it's called default, and that's the only one that you can call when you don't have any values available to pass as parameters.

Still with me?

If you're still with me, then maybe you see the problem already: How can you call a no-argument constructor if it doesn't exist? And the language is automatically trying to call it... uh-oh.

Fortunately, there is a way out of this. We can tell the compiler what constructor to use for the members and bases, using something called an initialization list. It looks like this:


...
public:
Circle() : myApple(parameters, for, apple, constructor, go, here);
// You can use any one of the Apple constructors, as long as you have the
// correct number and type of parameters.


Of course, you have to be able to determine the parameters right at that spot. If you're defining a Circle constructor that takes parameters, then you might use this to "forward" those parameters (or some of them) to the Apple constructor. Or you might use constant values. Or perform some kind of calculation on the Circle parameters. Or some combination of all of those. (If you think you need to read global variables here, there is almost certainly something very wrong with your design.)

Using the initialization list has many advantages. First off, as noted, sometimes you have to do it. It's cleaner because you're actually explainng how to initialize data members, instead of letting the compiler do its thing and then overwriting that work (by assigning values in the constructor body). As a result, it can't be slower, and might (not likely; compilers are good at optimizing this kind of thing) be faster. Oh, and a lot of the time, you end up not having to write anything in the constructor body at all. :)

Share this post


Link to post
Share on other sites
Quote:
Original post by X Abstract X
If I construct objects in a class' constructor, aren't they going to go out of scope as soon as the constructor is done executing?


If you have local variables that are of object type, then yes; the constructor is just like any other function, in this regard. But if this is happening, it's almost certainly because it's exactly what you want to happen.

If you're talking about initializing the data members of the class, then no; everything that's part of the class is still part of the class after the constructor ends. But that is not "constructing objects". When you run the constructor, the data members have already been initialized (see my previous post). You can overwrite this initialization, or do other sorts of extra work in order to "construct" the current object. The parts of the whole object were already constructed ahead of time. You merely set their values.

This works the same way as in Java. A data member in C++ is like a field in Java. (In this case, it's pretty much just different words for the same thing; each language uses its own terms for historical reasons.)

Quote:
Does this mean I should declare all my objects on the heap and manage them myself?


No! Definitely not. In C++, you should keep things on the stack unless you have a reason for them to go on the heap, and you should not manage the memory yourself, but instead use tools (such as container classes) to take care of it for you.

Share this post


Link to post
Share on other sites

This topic is 2848 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this