Sign in to follow this  

C++ Question About Objects

This topic is 815 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

When creating an object in C++ I would like to create the object and call a function inside that object at the same time. For instance, say I have a "Level" class and inside that class there is a function that loads the level called "load(string level)".

 

Instead of doing this:

Level level;
level.load("level1");

Is there any way to do something like this:

Level level = new Level("level1").load; // I believe this is possible in Java, however it has been quite a while since I programmed in Java.

And I know that the "new" keyword functions a lot different in C++ than it does in Java, so I have been reluctant to try anything that included using it. It is not that big of an issue I just think it looks nicer when it's all on one line.

Edited by Dark Sage

Share this post


Link to post
Share on other sites

That makes sense. Guess it's just because I haven't learned about destructors yet, and I would assume that if I am doing the level loading in the constructor I would have to destruct the old level before loading another one. I could just be over complicating it though...

Share this post


Link to post
Share on other sites

Hello, you're mixing up a couple of things.

Firstly, you want to do stuff on the same line. This is easier than you think:

Level level; level.Load("level1");

Tadaa! However, in general, it is more readable to use shorter lines, especially since debuggers usually work on a per line basis. So, stepping through the line above will likely be quite awkward.

 

Secondly, you're talking about new, constructors and destructors.

Let me try to untangle this a bit.

 

Whether you use "new" or not, an objects constructor and destructor will still be run (if it has any). So they don't have anything to do with the use of "new".

 

Instead, "new" will change where the object will life and therefore influence it's lifetime.

In short, without "new", the object will live until the current scope ends (at the next "}"). With "new", the object will live until "delete" is called on it.

For a more detailed explanation, this looks to be fairly comprehensive:

http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/

 

For the sake of completeness, here's how the above example would work with "new", again as a single line.:

Level* level = new Level(); level->load("level1");

I hope that helps!

Share this post


Link to post
Share on other sites

Hello, you're mixing up a couple of things.

Firstly, you want to do stuff on the same line. This is easier than you think:

Level level; level.Load("level1");

Tadaa! However, in general, it is more readable to use shorter lines, especially since debuggers usually work on a per line basis. So, stepping through the line above will likely be quite awkward.

 

Secondly, you're talking about new, constructors and destructors.

Let me try to untangle this a bit.

 

Whether you use "new" or not, an objects constructor and destructor will still be run (if it has any). So they don't have anything to do with the use of "new".

 

Instead, "new" will change where the object will life and therefore influence it's lifetime.

In short, without "new", the object will live until the current scope ends (at the next "}"). With "new", the object will live until "delete" is called on it.

For a more detailed explanation, this looks to be fairly comprehensive:

http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/

 

For the sake of completeness, here's how the above example would work with "new", again as a single line.:

Level* level = new Level(); level->load("level1");

I hope that helps!

Thanks for your help and information. Clears up a few things I was definitely confused about haha.

Share this post


Link to post
Share on other sites

A final note FYI.

Do not call overriden functions (pure virtual) from base class ctor. So you cannot do something like:

class Asset {
public:
  Asset(const std::string &foo) { Load(foo); }
protected:
  virtual void Load(const std::string &foo) = 0;
};

class Level : public Asset {
public:
  Level (const std::string &foo) : Asset(foo) { }
protected:
  void Load(const std::string &foo) {
    // Pull physics
    // Pull textures
    // Pull sound resources
  }
};

To build a Level object the runtime first builds the Asset object. When the Asset object ctor is run, it has no information about what's really running and you'll be screwed big way. I think some compilers warn you or even prevent you from doing that. I am 100% sure I have been screwed in the past.

If memory serves, Java allows this for some reasons I don't remember. I'd suggest to be careful with that.

 

EDIT: see Brother Bob for a more "technically correct" explanation. I still suggest to stay away from those things but that's opinion at this point.

Edited by Krohm

Share this post


Link to post
Share on other sites

Level (const std::string &foo) : Asset(foo) { }

 

Careful with that.

 

How long does loading a level take?  A half second?  Five seconds? Ten seconds? Two minutes?

 

Temporary objects get created all the time.  Sometimes you want to create empty objects, such as when you allocate an array of things.

 

It is generally best to provide a default constructor that does nothing except create an empty object, and a copy constructor that generally works with shallow copies of members. In this case the default constructor would be an unloaded level. This should only initialize the values needed to specify the level is unloaded, and return immediately.

 

You can still write constructors with parameters like that, internally they call the load function and wait for the seconds or minutes required to do the job.  But make sure those are not the ONLY constructor you create.  Build an instantly constructable default as well.

Share this post


Link to post
Share on other sites

A final note FYI.

Do not call overriden functions (virtual) from base class ctor. So you cannot do something like:

class Asset {
public:
  Asset(const std::string &foo) { Load(foo); }
protected:
  virtual void Load(const std::string &foo) = 0;
};

class Level : public Asset {
public:
  Level (const std::string &foo) : Asset(foo) { }
protected:
  void Load(const std::string &foo) {
    // Pull physics
    // Pull textures
    // Pull sound resources
  }
};

To build a Level object the runtime first builds the Asset object. When the Asset object ctor is run, it has no information about what's really running and you'll be screwed big way. I think some compilers warn you or even prevent you from doing that. I am 100% sure I have been screwed in the past.

If memory serves, Java allows this for some reasons I don't remember. I'd suggest to be careful with that.

 

Java and C# allow this because the construction of a derived object runs in the opposite fashion from a C++ object. In Java/C# first the derived object is created with its associated vtable, this means that the constructor knows where to dispatch a virtual function call too. In C++ first the base object is created and then the derived version, calling a virtual function is in that case undefined behaviour for C++.

Share this post


Link to post
Share on other sites

 In C++ first the base object is created and then the derived version, calling a virtual function is in that case undefined behaviour for C++.

 

Calling virtual functions form the base class constructor is perfectly fine and well specified. During construction of the Asset base class, the concrete type of the object is Asset (the concrete type is not Level until later during construction) and the virtual call is dispatched to Asset::Load.

 

Since Asset::Load is pure there is a chance it also has no implementation. In that case I believe the behaviour of calling Load is undefined. Otherwise, there are no problems calling virtual functions other than ones understanding of the rules.

Share this post


Link to post
Share on other sites

In C++ first the base object is created and then the derived version, calling a virtual function is in that case undefined behaviour for C++.

Calling virtual functions form the base class constructor is perfectly fine and well specified. During construction of the Asset base class, the concrete type of the object is Asset (the concrete type is not Level until later during construction) and the virtual call is dispatched to Asset::Load.
 
Since Asset::Load is pure there is a chance it also has no implementation. In that case I believe the behaviour of calling Load is undefined. Otherwise, there are no problems calling virtual functions other than ones understanding of the rules.


C++'s rules for virtual dispatch in constructors and destructions are well-defined, yes, but are generally not what people expect or want when they do that. So it is usually discouraged to avoid confusion and surprises.

Share this post


Link to post
Share on other sites

 

A final note FYI.

Do not call overriden functions (virtual) from base class ctor. So you cannot do something like:

snip

To build a Level object the runtime first builds the Asset object. When the Asset object ctor is run, it has no information about what's really running and you'll be screwed big way. I think some compilers warn you or even prevent you from doing that. I am 100% sure I have been screwed in the past.

If memory serves, Java allows this for some reasons I don't remember. I'd suggest to be careful with that.

 

Java and C# allow this because the construction of a derived object runs in the opposite fashion from a C++ object. In Java/C# first the derived object is created with its associated vtable, this means that the constructor knows where to dispatch a virtual function call too. In C++ first the base object is created and then the derived version, calling a virtual function is in that case undefined behaviour for C++.

 

I suspected it was something about that... how do they deal with object invariant BTW? There's no guarantee the clear-to-zero init produces a correct premise for the called functions anyway.

Share this post


Link to post
Share on other sites

A final note FYI.
Do not call overriden functions (virtual) from base class ctor. So you cannot do something like:



snip
To build a Level object the runtime first builds the Asset object. When the Asset object ctor is run, it has no information about what's really running and you'll be screwed big way. I think some compilers warn you or even prevent you from doing that. I am 100% sure I have been screwed in the past.
If memory serves, Java allows this for some reasons I don't remember. I'd suggest to be careful with that.

 
Java and C# allow this because the construction of a derived object runs in the opposite fashion from a C++ object. In Java/C# first the derived object is created with its associated vtable, this means that the constructor knows where to dispatch a virtual function call too. In C++ first the base object is created and then the derived version, calling a virtual function is in that case undefined behaviour for C++.

I suspected it was something about that... how do they deal with object invariant BTW? There's no guarantee the clear-to-zero init produces a correct premise for the called functions anyway.


Dunno if I'm answering the question correctly cause I'm not hugely familiar with java, but there is no "clear-to-zero" init in C++. Structs and classes get their constructors called, other types do not get constructed (unless the wrapping object calls their constructors). Since you can't access any variables in derived types from functions in base types, the base type functions never see your object in an uninitialized state (unless called from the constructor itself).

Which is another reason why virtual dispatch doesn't go to most-derived in constructors/destructors because otherwise those functions could see their data in a non-constructed or destructed state.

Share this post


Link to post
Share on other sites

This topic is 815 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