Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create class member objects initialized during the constructor

Tags:

c++

syntax

I am primarily a c# programmer but a project I am working on has me using c++. In C# I have the ability to define a member of a class where the member is null until it is initialized. Like so:


Class Foo{
    private Bar _bar;
    public Foo(int valueBarNeeds){
        _bar = new Bar(valueBarNeeds);
    }
}

The value of _bar is null and access is prohibited until it is initialized. The rationale for this use case is that the constructor for the private object relies on some value that is not known until the parent class is constructed.

Now, in C++ I try and do the same thing:


class Foo{
public:
    Foo(int valueBarNeeds){
        _bar = new Bar(valueBarNeeds);
    }
private;
    Bar _bar;
};

The compiler throws an error saying that there is no constructor for bar that takes zero arguments. My understanding is, in C++ the new keyword means something completely different. As a part of this difference, one is able to define objects that get disposed at the end of a method without needing a manual deletion by declaring without the new keyword.


SomeFunc(){
    int valueBarNeeds = 100;
    Bar _bar(valueBarNeeds);
    _bar.SomeFunc();
}

_bar is deleted when the methods stack goes out of scope.

This then sets up my question. If the syntax that I use in C# to create unitialized objects actually tries to initialize objects in C++... How do I create an unitialized type accesible to the rest of the class methods, that gets built by the parent objects constructor?

like image 475
Dabloons Avatar asked Nov 10 '13 22:11

Dabloons


People also ask

Can we initialize object in constructor?

A constructor in Java is a special method that is used to initialize objects. The constructor is called when an object of a class is created. It can be used to set initial values for object attributes.

How do you initialize a data member in a constructor?

Const member variables must be initialized. A member initialization list can also be used to initialize members that are classes. When variable b is constructed, the B(int) constructor is called with value 5. Before the body of the constructor executes, m_a is initialized, calling the A(int) constructor with value 4.

How does a constructor initialize an object in Java?

In Java, a constructor is a block of codes similar to the method. It is called when an instance of the class is created. At the time of calling constructor, memory for the object is allocated in the memory. It is a special type of method which is used to initialize the object.


2 Answers

The problem is that what you're calling "initialisation" is actually no such thing. Any members that are initialised, implicitly or explicitly, are initialised before the program enters your constructor body.

Your code snippets show only assignment; it doesn't matter that you're doing this in the body of a constructor for the encapsulating object. It's still just assignment.

Bar is a class so your member _bar will be implicitly initialised, but it actually cannot be because the class has no constructor taking no arguments. In order to provide arguments, you have to explicitly initialise the member yourself.

In C++ we initialise members like this:

class Foo {
public:
    Foo(int valueBarNeeds)
     : _bar(valueBarNeeds)
    {}
private:
    Bar _bar;
};

You are also right in that you are misunderstanding new a little; unlike in Java, it should be used sparingly, as objects are fundamentally created by simply declaring (and, where necessary, defining) them. The use of new is reserved for dynamic allocation in the free store and returns a pointer for use; this usage should be rare. You successfully fixed this in your final code snippet.

How do I create an unitialized type accesible to the rest of the class methods, that gets built by the parent objects constructor?

If the member is of a class type, it will always be initialised. You can't have an object that doesn't exist. The closest you can get is to encapsulate a pointer rather than an object:

class Foo {
public:
    Foo(int valueBarNeeds)
     : _bar(nullptr)
    {
       // some time later...
       _bar = new Bar(valueBarNeeds);
    }
private:
    Bar* _bar;
};

But this opens up a can of worms as regards memory management and whatnot and, as explained above, you should avoid it unless you really need it. Alternatives include smart pointers but you should still consider sticking with the bog-standard object encapsulation where possible. It should be rare that you need to deliberately leave an object in an invalid state for a time.

like image 75
Lightness Races in Orbit Avatar answered Oct 13 '22 19:10

Lightness Races in Orbit


You give your class a data member of that type, and initialize it in the constructor's initialization list:

class Foo
{
 public:
     Foo(int valueBarNeeds) :_bar(valueBarNeeds) {}
 private:
     Bar _bar;
};

Once you are in the constructor's body, all data members have been initialized. If you do not initialize them explicitly in the constructor initialization list, they get default initialized, which means the default constructor is called for user defined types, and no initialization is performed for built-in types.

like image 45
juanchopanza Avatar answered Oct 13 '22 18:10

juanchopanza