Advertisement

C++ Question About Objects

Started by September 21, 2015 05:40 AM
11 comments, last by SmkViper 9 years, 3 months ago

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.

If all you are actually concerned about is the syntax and the separate call to load, then just do the loading in the constructor instead of in a separate load function.

Level level("level1");
Advertisement

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...

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!

Oh, another thing: In Java, objects are *always* on the heap, so you don't have a choice to make there. Only primitives (int, float,...) are on the stack.

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.

Advertisement

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.

Previously "Krohm"


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.

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++.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

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.

This topic is closed to new replies.

Advertisement