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?
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With