I feel really stupid but I have some trouble finding the right search terms for this (probably easy) question. I think that with some code my issue is easy to understand.
I have a class that has, as a member, an instance of another class. So I go:
class Engine {
sf::Window window_;
}
Then in my .cpp file:
Engine::Engine() {
window_ = sf::Window(200,100);
}
I actually didn't know this was the wrong way to do things until I got "Object of type sf::Window cannot be assigned because its copy operator is implicitly deleted" for this particular class. I understand that I'm supposed to do sf::Window window(200,100), but how do I combine that with creating a member variable in my class (window_)?
You need to use the constructor initialization list to initialize data members:
Engine::Engine() : window_(200,100)
{
}
What you are attempting to do is to assign to a default constructed instance. This is because, once you are in the constructor's body, all data members (and base classes) have already been initialized.
You can either do it via member initialization list
Window() : window_(sf::VideoMode(640, 480), "title") {}
or by calling window_.create(arguments)
Related
There are many C++ programming best practices that are proposed in many articles and books. Following is a subset that is related to C++ class data members:
Make sure that objects are initialized before they are used.
Make sure that all constructors initialize everything in the object.
It is usually more effective to initialize data members in the initializer list of each constructor than in its body.
In the initializer list, data members should be listed in the order they are declared.
Consider the following class with data members of Qt class types:
class MyClass {
public:
myClass();
~myClass();
private:
int myInt;
QString myQString;
QList<QString> myQList;
QHash<int, QString> myQHash;
char * pChar;
};
By applying the above best practices, the constructor code would look like the following:
MyClass::MyClass() :
myInt(0), // OK, primitive should be initialized.
myQString(), // Is this really needed?
myQList(), // Is this really needed?
myQHash(), // Is this really needed?
pChar(NULL) // OK, pointer should be initialized.
{
}
However, I have the impression that not all of the Qt class data members need to be initialized. But I am not 100 % sure of this. Some developers argue that by putting all the data members in the initialization list, we may avoid omitting the initialization of some important data members that should be initialized. However, if this is a real concern, I would prefer putting a comment line for each data member that does not need to be initialized, for example:
MyClass::MyClass() :
myInt(0),
//myQString(),
//myQList(),
//myQHash(),
pChar(NULL)
{
}
To summarize, I would like to know when a Qt class data member should be initialized, and when the initialization is not needed, and why. Thanks!
If you don't have a default constructor of a class then you must initialize it in initializer list, and it is not required to call default constructor in initializer list. It is not Qt specific it is a general rule for any class. When you have a default constructor(which takes 0 argument) even if you don't call it in initializer list, it will be called automatically.
Update:
Q1: Are the 2 versions of MyClass::MyClass() above equivalent? That
is, do they produce 2 objects of same content?
Yes.
Q2: Is one version faster than the other?
You can type the second version faster ;-), there is no performance difference.
Default constructor of QObject's will be called regardless you call it explicitly, or it's called implicitly when your object is created.
You may put a debug message into QObject constructor code and see for yourself, it's Open Source for truth's sake! :)
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
This is really question on C++ language, what does SNeuron(int NumInputs); mean inside the structure? I'm not c++ programer and this construction inside structure looks strange to me. Can anybody explain it what it could be for? I already tried google.
struct SNeuron
{
//the number of inputs into the neuron
int m_NumInputs;
//the weights for each input
vector<double> m_vecWeight;
//ctor
SNeuron(int NumInputs);
};
A struct in C++ is exactly the same as a class, except that all members of a struct are public by default.
So what you are seeing here is simply a constructor declaration for the struct.
The reason, I believe, is to make interoperability with C easier.
It's simply declaring a constructor for the struct SNeuron. This is called a prototype method, and won't wok unless it's implemented later on. It could be implemented inside the class by saying
SNeuron(int NumInputs) {
// Constructor code
}
or outside like this:
SNeuron::SNeuron(int NumInputs) {
// Constructor code
}
The main use of this would be to initialize the fields m_NumInputs and m_vecWeight.
When an instance of the structure is created, it need to be "constructed" (i.e. initialized), that is done by having constructor functions, which are automatically called by the compiler when an instance is created.
For example, in the following declaration and definition of a variable using the structure, the constructor will be called:
SNeuron myNeuron(5); // Creates the instance and calls the constructor function
That is simply a constructor. A constructor is basically a mechanism by which you initialize all the data members of a class when an object of that class type is created.
You can write constructors for both struct and class.
But that constructor which you declared in your code is not the default constructor because a default constructor is that constructor which takes no arguments.
I have two classes, one has permitted making the only explicitly declared constructor, the no arguments one, private. I recently added another class but am getting compile-time errors due to having made the no argument constructor private. The only difference is the first had a public static factory method while the latter has a non-static constructor which takes an argument.
Thanks, hope this makes some sense.
Okay, I give you some code:
This doesn't compile:
class GridElem {
public:
GridElem(const char _idata);
~GridElem();
private:
GridElem();
}
This does compile:
class GridElem {
public:
GridElem(const char _idata);
~GridElem();
GridElem();
}
This does compile:
class MyClass {
public:
~MyClass();
private:
MyClass();
Not a complete example, sorry, but I believe this shows where the anomally arises, perhaps from extending cocos2d::Layer?
EDIT
Alright I found the call that is doing this (eclipse couldn't find it :()
in header
GridElem myGrid[15][15];
in cpp file
MyClass::MyClass() : myGrid{0} {}
I only recently changed it from a smaller grid and giving each element explicitly (because it was still just 0 for want of more information), I think this must now expand to parameterless c'tor. I completely forgot that, sorry, but it wasn't 100% obvious mistake.
You can always make the default constructor private (or not have a default constructor at all).
What you can't do is use a private default constructor from outside the class (or its friends).
You haven't provided enough context to know for sure, but I suspect your problem is that something else in your code is trying to default construct a GridElem, so it needs to be public.
The only difference is the first had a public static factory method while the latter has a non-static constructor which takes an argument.
If MyScene has a factory method then that's a member and can call the private default constructor. There's no "anomaly", you've just said that both types can only be default constructed by their own member functions (and friends), but only one of them has a member function to actually do that.
making default constructor private usually means you want all
creation to go through a factory. So use said factory, or make it public
I am rewriting some code to eliminate global variables and made a class constructor/destructor handle cleanup of some third party library resources, but I am concerned about some code which initializes one member from another member in the class initializer list.
class MyPodofoDocument {
public:
// generates pdf to stream
MyPodofoDocument(std::stringstream *pStringStream)
: device(pStringStream), document(&device)
{
}
private:
PoDoFo::PdfOutputDevice device;
PoDoFo::PdfStreamedDocument document;
PoDoFo::PdfPainter painter;
};
The code which uses this class doesn't need to see all the details that go into using the library, but the way I hide them makes it dependent on using members to initialize other members, before it hits the constructor's actual code block, where it has a valid this pointer.
It works in a unit test skeleton, so my question is basically, "Is this okay, portable and safe?"
The members are initialized in the order they are declared, top to bottom
PoDoFo::PdfOutputDevice device;
PoDoFo::PdfStreamedDocument document;
PoDoFo::PdfPainter painter;
so it is safe to use device to initialize document.
Kind of. The rules is that the member variables are initialised in the order they are declared in the class declaration.
In your case, it is fine since device is declared before document.
However, in the following case, we have undefined behaviour, despite the order of the initialiser list.
class A {
public:
A(int i) : b(i), a(b) { }
private:
int a;
int b;
}