Explicitly initialize member which does not have a default constructor - c++

I´m trying to instantiate an object which has no default constructor so it can be referenced from any methods inside the class. I declared it in my header file, but the compiler says that the constructor for the class creating it must explicitly initialize the member, and I can´t figure out how to do that.
Really appreciate your answers, thank you in advance!
The snippet:
MyClass.h
include "MyOtherClass.h"
class myClass {
private:
MyOtherClass myObject;
public:
MyClass();
~MyClass();
void myMethod();
}
MyClass.cpp
include "MyClass.h"
MyClass::MyClass() {
MyOtherClass myObject (60);
myObject.doSomething();
}
MyClass::myMethod() {
myObject.doSomething();
}
MyOtherClass.h
class MyOtherClass {
private:
int aNumber;
public:
MyOtherClass (int someNumber);
~MyOtherClass();
void doSomething();
}
MyOtherClass.cpp
include "MyOtherClass.h"
MyOtherClass::MyOtherClass (int someNumber) {
aNumber = someNumber;
}
void MyOtherClass::doSomething () {
std::cout << aNumber;
}

You are almost there. When you create an object in C++, by default it runs the default constructor on all of its objects. You can tell the language which constructor to use by this:
MyClass::MyClass() : myObject(60){
myObject.doSomething();
}
That way it doesn't try to find the default constructor and calls which one you want.

You need to initialize the myObject member in the constructor initialization list:
MyClass::MyClass() : myObject(60) {
myObject.doSomething();
}
Before you enter the body of the constructor all member variables must be initialized. If you don't specify the member in the constructor initialization list the members will be default constructed. As MyOtherClass does not have a default constructor the compiler gives up.
Note that this line:
MyOtherClass myObject (60);
in your constructor is actually creating a local variable that is shadowing your myObject member variable. That is probably not what you intended. Some compilers allow you turn on warnings for that.

There are two errors
Your code MyOtherClass myObject(60); is not initializing the member of the class, but it's instead declaring a local variable named myObject that will hide the member inside the constructor. To initialize a member object that doesn't have a default constructor you should use member initialization lists instead.
You are trying to learn C++ by experimenting with a compiler.
This second error is the most serious error and if not corrected is going to take you to a terribly painful path; the only way to learn C++ is by getting one or two good books and read them cover to cover. Experimenting with C++ doesn't work well.
No matter how smart you are there's no way you can guess correctly with C++, and in a sense being smart is even dangerous (because you may be tempted to skip over something "you understood already"): the reason is that it happens in quite a few places that the correct C++ way is illogical and consequence of historical evolution of the language.
In many places C++ is the way it is because of history and not because it makes sense, and no matter how smart you are there's no way you can deduce history... history must be studied.

MyClass::MyClass(): myObject (60){
myObject.doSomething();
}
Initialization of the data member ends before constructor function body.in the function body you just assign

Related

How to instantiate instance variable without copy constructor and assignment operator

I am using a library with a class that does not have an assignment operator implemented and the copy constructor is disabled. I can instantiate a local instance of LibraryClass named var like this:
LibraryClass var(data, (char *)fileName, results);
But I want to create a LibraryClass instance variable on the class I am writing. Then I want to instantiate it in the class constructor. Something like this:
class MyClass
{
LibraryClass var;
void MyClass();
}
MyClass::MyClass()
{
var = LibraryClass(data, (char *)fileName, results);
}
In this case I end up with
error: ‘LibraryClass& LibraryClass::operator=(const LibraryClass&)’ is private
LibraryClass& operator=(const LibraryClass& rOther); // no implementation
I have tried everything I can imagine to make this work but nothing is working. Is what I am attempting to do even possible? I am out of ideas so any suggestion is much appreciated.
EDIT
I'm not actually instantiating the variable in the constructor. It's happening in a separate function. I only said constructor because I mistakenly thought it was just a simplifying assumption. I didn't realize that the initialization list would solve that problem. The main question I want to answer is the title.
How can I instantiate an instance variable of a class that doesn't have a copy constructor or assignment operator? Or is the initialization list the only way to do it?
You need to use the initialization list.
Constructors and member initializer lists
MyClass::MyClass() :
var(data, (char*) fileName, results))
{
}

Why do we need a default constructor to pass an object by reference in C++?

My C++ compiler give me an error "no default constructor exists for class Foo" when I try the following.
MyClass::MyClass(const Foo& foo)
{
...
}
If I'm passing a reference, the object should already be initialized, correct? And it's not a problem with copy constructors, because I defined one explicitly. So why would one need a default constructor to pass a reference?
The only thing I've been able to think of is that it might not know how much memory to allocate for it. If that's the problem, is there a way to tell the compiler that I only ever intend to allocate this object dynamically? I haven't been able to find any answers online for this, and I would really appreciate some help.
EDIT: I'm just going to edit in my actual code.
MemberManager.cpp:
#include "MemberManager.h"
MemberManager::MemberManager(const NodeManager& nodeSet, std::vector<int> cctMat, int n)
{
for(int i = 0; i < n; i++)
{
memSet[i] = Member();
}
}
NodeManager.h
#include "Node.h"
class NodeManager
{
public:
//constructors
NodeManager(std::vector<double> crdMat, std::vector<Constraint> cstMat, int n):
nodeSet(n) {};
//copy
NodeManager(const NodeManager& src):
nodeSet(src.nodeSet) {};
}
My precise error message is a red underline under the first body bracket of MemberManager::MemberManager(...) and it says no default constructor exists for NodeManager. This is my intent, but I don't understand WHY it would need a default constructor.
You don't need a default constructor to pass an object by reference. Your code must be doing something else that requires such a thing.
My guess is that MyClass has a member of type Foo. If it isn't default-constructible, then it needs to be initialised in its declaration, or in the constructor's initialiser list:
MyClass::MyClass(const Foo& foo) : foo(foo) { ... }
^^^^^^^^
initialiser list
This assumes that the member is called foo, and that it's supposed to be initalised by copying the function parameter.
It would be helpful to know what compiler you are using, which standard of c++ it complies to and if you have other constructors for MyClass.
What I can imagine is that the compiler does not generate a default constructor MyClass() because you have defined another constructor. Should the compiler ever want to generate a default object of class MyClass like in
class MyClass mc;
The only way to accomplish this in the absence of MyClass::MyClass() is to think the code line above as
class MyClass mc( Foo() );
This requires class Foo to have a default constructor.
I would have made this a comment, but I'm not yet allowed to.

Can we avoid the default constructor in this case?

Observation: The constructor of ClassMain needs to call Init before it can constructor a member variable a. Since the ClassA has no default constructor, the code doesn't compile.
ClassA
{
public:
// This class has no default constructor
ClassA(...){}
};
class ClassMain
{
public:
ClassMain(...) {
Init(...);
a = ClassA(...); // error: ClassA has no default constructor
// a has to been constructed after the Init is called!
}
ClassMain(...) {
Init(...);
call other functions
a = ClassA(...);
}
private:
// initialize environment
void Init(...) {}
private:
ClassA a;
};
Question> The simple solution is to provide a default constructor for ClassA. However, I would like to know whether there is a better solution to address the issue above?
The better solution is not to require an Init function at all. You're trying to reinvent constructors, and breaking their design in the process.
If Init does too much work for a constructor, then do it outside and pass the resulting resources into ClassMain as a constructor argument; notice how you're already doing all the work in the constructor's scope anyway, thereby not gaining anything appreciable over proper initialisation.
Of course, if you must perform a ton of work before initialising a, and you cannot pass in a ClassA& from the outside and initialise from that, then you're simply going to have to have a be an indirect member.
There is one nasty workaround you could use: have Init actually be a base constructor...
The obvious solution is to call Init() from the initializer list of an early member or a base class. Once this subobject is constructed its results can be passed to the constructors of other subobjects. For example, when defining stream classes I typically privately inherit from a virtual base containing the stream buffer:
struct somebuf_base {
somebuf sbuf;
// ...
};
class somestream
: private virtual somebuf_base
, public std::ostream
{
public:
somestream(someargs)
: somebuf_base(someargs)
, std::ostream(&this->sbuf) {
}
// ...
};
Since base classes are constructed in the order they appear but virtual bases before non-virtual bases, the base class containing the sbuf member is constructed first. Its constructor replaces your Init() function.
When using C++ as of the 2011 revision, you might also use forwarding constructors to share logic between multiple constructors.
It's easier to take a pointer to ClassA; So, you can instantiate it whenever you want.(after the init())
If you used a pointer, don't forget to implement the virtual destructor and release the allocated memory for the ClassA *a
If you absolutely must call some function at the start of your constructor, and can't put that setup into some base class or early-constructed member, you could use this ugly trick:
ClassMain::ClassMain(int main_param)
: a( (Init(init_arg), class_a_arg1), class_a_arg2 )
{
}
In this case: No, we cannot avoid that.
The reason is that when calling Init or any other member function you are guaranteed by the language that the object you are in exists. As a is a member of ClassMain it must be constructed before any function in ClassMain can be called.
The only chance that you have here is to refactor the code.

How to create class member objects initialized during the constructor

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

Simple Question: Passing object with state, C++

I'm not an C++ expert and still do not have a great intuitive grasp of how things works. I think this is a simple question. I am having trouble passing objects with state to other objects. I'd prefer to avoid passing pointers or references, since once the initialized objects are setup, I call them millions of times in a tight loop. I think I'm dong something like a Command pattern. Here's the core of the problem. My header code is something like:
class ObjectWithState {
public:
ObjectWithState(int state) { // This constructor creates the problem!
state_ = state; // everyting works with no constructor.
}
private:
int state_;
};
class TakesObject {
public:
TakesObject(ObjectWithState obj) {
obj_ = obj;
}
private:
ObjectWithState obj_;
};
My main() functions looks like:
int main () {
ObjectWithState some_object(1);
TakesObject takes_object(some_object);
return 0
}
I get the following error (g++):
test.h: In constructor 'TakesObject::TakesObject(ObjectWithState)':
test.h:14: error: no matching function for call to 'ObjectWithState::ObjectWithState()'
test.h:5: note: candidates are: ObjectWithState::ObjectWithState(int)
test.h:3: note: ObjectWithState::ObjectWithState(const ObjectWithState&)
Simple answer?
I not sure if this has to do with copy constructors. If so, I'm trying to find a solution that keeps the class definition of ObjectWithState very clean and short. Users of this library will be defining lots of small functions like that which will be used by TakesObject function. Ideally programmers of the ObjectsWithState just need to focus on implementing a simple object. Perhaps I'm going astray...
What you may want to do is use the member initialisation syntax:
class TakesObject {
public:
TakesObject(ObjectWithState obj): obj_(obj) {
}
private:
ObjectWithState obj_;
};
In your posted code, the TakesObject constructor will first try to construct a new ObjectWithState with its default constructor, then call the assignment operator to copy the passed-in obj to obj_. The above example constructs the obj_ directly using its copy constructor.
You will also need to define a copy constructor for your ObjectWithState class, too:
class ObjectWithState {
public:
ObjectWithState(int state) {
state_ = state;
}
ObjectWithState(const ObjectWithState &rhs) {
state_ = rhs.state_;
}
private:
int state_;
};
If you omit all constructors from your class declaration, then the compiler supplies a default and a copy constructor for you. If you declare any constructors, then the compiler supplies no default or copy constructor, so you must implement your own.
You're getting this error because you're declaring a constructor. The compiler will provide the default constructor only if you don't declare a constructor in your class. Because you have declared a constructor, you don't get the default one. You have to explicitly declare a constructor with no parameters.