In class MyClass, I have a member Dialog dialog_.
After MyClass's constructor is called, I want to call a different constructor for dialog_ with parameters that are created in MyClass's constructor (that's why I can't directly call the different constructor for dialog_, but just the default one).
So I tried
dialog_ = Dialog(/* different constr. w/ parameters passed from MyClass */);
But that doesn't work. The error is
Error: no operator "=" matches these operands
operand types are: Dialog = Dialog
So I Googled a bit and found in this SO thread (3rd answer) a code snippet which I tried:
dialog_.~Dialog();
new(&dialog_) Dialog(/* different constr. w/ parameters passed from MyClass */);
And it works. The answer in the thread though states "The value of this does not go beyond purely theoretical though. Don't do it in practice. The whole thing is ugly beyond description."
So what can I do to solve my problem without using that obviously frowned upon piece of code?
I hope you understand what I'm trying to achieve. Thanks!
There are two ways to achieve what you want.
In c++98 you need to defer some of your initialisation to an init() function that you call from the constructor. This is a bit icky because it means a redundant construction and assignment for a number of your member variables.
In c++11 you can call 1 other constructor in the initialiser list, passing computed values (these values can be computed in static functions for cleanliness).
If you provide an example of your constructor code I can show you how to do it.
You can put the Dialog member in a std::unique_ptr and then replace it when you need:
class MyClass {
private:
std::unique_ptr<Dialog> dialog_;
public:
MyClass():
dialog_( /* ... first constructor ... */ ) {}
void setNewDialog(/* parameters */) {
dialog_.reset(new Dialog(/* parameters */) );
}
};
Nothing I've tried is working, so I'll just use
dialog_.~Dialog();
new(&dialog_) Dialog(/* ... */);
even though it's bad
Related
I understood 'explicit' concept related to constructors in C++ which will take single parameter as input. But I read on some websites that we need to change the constructor to explicit, irrespective of the number of parameters the constructor will take as input.
Can any one please help me to understand below issues.
Why do we need to make a constructor as explicit if it doesn't take any input?
What is the use of making a constructor as explicit if it takes more than one parameter and all the parameters are not default?
Why do we need to make a constructor as explicit if it doesn't take any input?
That seems incorrect to me. A constructor needs to be explicit if you don't want the constructor to be called automatically.
Say you have:
struct Foo
{
Foo() {}
Foo(int) {}
};
void bar(Foo)
{
}
Then,
bar(1);
will work. It is translated as:
bar(Foo(1));
If there is a default constructor, i.e. one that does not take any arguments, there is nothing to convert from. You may not use:
bar();
and hope to get it translated as:
bar(Foo{});
What is the use of making a constructor as explicit if it takes more than one parameter and all the parameters are not default?
This one has some validity.
If you had:
struct Foo
{
Foo() {}
Foo(int, int) {}
};
void bar(Foo)
{
}
You may not use
bar(10, 20);
or
bar((10, 20));
and hope to have it translated as:
bar(Foo(10, 20));
However, you may use:
bar({10, 20});
and it will be translated as:
bar(Foo{10, 20});
If you want to prevent use of this syntax, bar({10, 20}), you may make the constructor explicit. IMO, this has less utility. The potential for inadvertently misusing a constructor with one argument is real. The potential for inadvertently misusing a constructor with more than one argument is very small.
Just to complement #R Sahu's answer from a different perspective:
The recommendation to use explicit for every constructor irrespective of how many arguments it takes can steam from the fact that strictly speaking every C++ constructor should be explicit by default and instead we would use implicit keyword: why constructors aren't explicit by default?
I saw this problem so many times: initially a class has a default constructor. Then after a while it's modified and a parameter is added. It's very easy to forget to add explicit in this case.
It's even easier to forget to add explicit when you remove a parameter from a two-arguments constructor. Also often your initial explicit one-parameter constructor got additional parameters or lost its parameter but explicit was left by mistake and compiler doesn't complain about this.
After a while your code starts to look like a christmas tree with many constructors that should be explicit but are not and others that are but shouldn't.
I suppose it's the reason why the website you mentioned recommends to use explicit always.
This is a short question about syntax in c++:
class arrayInit {
public:
bool vars[2];
arrayInit() : vars() {} //1
};
class array {
public:
bool vars[2];
array() {} //2
};
What does 1 and 2 do?
Why they don't zero initialize like this: bool vars[2]={};?
What is the purpose of arrayInit() : and array()? and what is it called so I could search for it?
It's from: https://msujaws.wordpress.com/2010/06/16/initializing-an-array-in-c/
What does 1 and 2 do?
Both 1 and 2 define the default constructor for the respective type
Why they don't zero initialize like this: bool vars[2]={};?
They could if they were using a compiler with c++11 support. Also var() will value initialize the array which is same as vars[2] = {} will explicitly initialize all elements to false
What is the purpose of arrayInit() : and array()? and what is it
called so I could search for it?
They are called the default constructors. C++ compiler will create them for you unless you want to do something special in them. If you were mentioning about what is written beyond the : (colon), that expression is called the initializer list
Read more here
What does 1 and 2 do?
Both allow you to override the default initialization for an array.
InitArray is specifically initializing the vars array with no parameters, I believe it will assume 0 as the default parameter.
Array is not specifically initializing the array, so it is falling back to a default initialization case.
Why they don't zero initialize like this: bool vars[2]={};?
You could do this, this is just another option which encapsulates the bool array in a class to allow you to provide other functionality if you wish.
What is the purpose of arrayInit() : and array()?
If you want default functionality, there is no need to encapsulate the array in its own class. Encapsulation allows you to encapsulate a type to provide different functionality from the default, you could go on to add methods for addition, subtraction, or anything you can think up and have it perform the methods in the way that you specify.
and what is it called so I could search for it?
Good question; Encapsulation, class initialization, array initialization.
http://www.cplusplus.com/doc/tutorial/classes/
Both arrayInit() and array() are default constructors. If the default constructor is missing and other constructors are available, you cannot declare an object from that class type without calling the other constructors e.g. you cannot do this arrayInit arr; without the default constructor.
The part : vars() is called the initialization list. You can read more about them in this link: http://en.cppreference.com/w/cpp/language/initializer_list
I am working in c++.
my class animation.h is the following:
class Animation
{
public:
Animation(ofVec2f _startLoc, ofVec2f _endLoc, float _speed, float _accel);
virtual ~Animation();
};
then in sceneMusic.h I have another class that calls animation class.
#include "animation.h"
class sceneMusic
{
public:
sceneMusic();
virtual ~sceneMusic();
private:
Animation staveMotion;
};
and sceneMusic.cpp
sceneMusic::sceneMusic()
{
staveImg.loadImage("./sceneMusic/stave_white.png");
staveMotion = Animation(ofVec2f(29, -staveImg.height()), \
ofVec2f(29, 249), 1, 0.1);
}
The above gives the following (expected) error:
src/awards/sceneMusic.cpp|3|error: no matching function for call to ‘Animation::Animation()’|
src/awards/sceneMusic.cpp|5|note: candidates are:|
src/Animation.h|14|note: Animation::Animation(ofVec2f, ofVec2f, float, float)|
src/Animation.h|14|note: candidate expects 4 arguments, 0 provided|
I read alot of threads that suggest I should use initializer lists and do in sceneMusic.cpp
sceneMusic::sceneMusic()
:Animation(ofVec2f(29, -staveImg.height()), \
ofVec2f(29, 249), 1, 0.1)
{
staveImg.loadImage("./sceneMusic/stave_white.png");
}
or something similar.
The problem is that the height of staveImg will only become available once the constructor will be executed.
Also the class sceneMusic does not inherit class animation, therefore I am not sure how the above would work. If I attempt to run the above I get
src/awards/sceneMusic.cpp|4|error: type ‘Animation’ is not a direct base of ‘sceneMusic’|
src/awards/sceneMusic.cpp|4|error: ‘((sceneMusic*)this)->sceneMusic::staveImg.ofImage_<unsigned char>::height’ cannot be used as a function|
src/awards/sceneMusic.cpp|5|error: no matching function for call to ‘Animation::Animation()’|
src/awards/sceneMusic.cpp|5|note: candidates are:|
...
What am I doing wrong ?
thank you for your help
Well, the issue with your second attempt is you'd need to do this:
sceneMusic::sceneMusic()
:staveMotion(ofVec2f(29, -staveImg.height()), \
ofVec2f(29, 249), 1, 0.1)
You specify the member names in the initializer lists. You specify a class name only when you are attempting to call a specific super-class constructor. Animation is not a super-class of sceneMusic.
The following "no matching function for call to Animation::Animation()" occurred for the same reason it would have occurred if you didn't have anything in your initializer list at all: the staveMotion member was still trying to use Animations default constructor (just like the default constructor is used when you declare a variable Animation a;), but Animation does not have a default constructor.
Correcting the error in the initializer list takes care of both errors.
By the way, your second error regarding height(): make sure there's actually a member function named height(). You aren't showing the code but that error seems to indicate that you actually have a member variable named height, not a function.
However, the above still won't fix your issue with having to call loadImage first (thanks chris for reminding me about that in comments).
The easiest solution to that is to revert to your first attempt, and simply provide a default (no parameter) constructor for Animation. As soon as you declare a non-default constructor, the compiler no longer generates a default constructor for you, and you have to explicitly declare/define Animation::Animation() to provide it. That way, staveMotion can be constructed with some default values (and won't have to be constructed in your initializer list) and then assigned to a proper value later.
A second option, by the way, that wouldn't require creation of temporary default Animations first (or perhaps more importantly, wouldn't require you to implement a default constructor that possibly breaks class invariants), would be to have staveImg be a member field of sceneMusic, give it a constructor that takes an image filename and loads the image, and declare it before staveMotion in the member list. You wouldn't need an Animation default constructor for this, and you could initialize everything in the initializer list:
sceneMusic :: sceneMusic () :
staveImg("./sceneMusic/stave_white.png"),
staveMotion(ofVec2f(29, -staveImg.height()), ofVec2f(29, 249), 1, 0.1)
{
}
A variation on that option is to construct the image ahead of time and pass it as a parameter to the sceneMusic constructor. This wouldn't require a new constructor fo staveImg.
A third option, which CantChooseUsernames brought up in the comments, is to make staveMotion a pointer. You can initialize it to NULL and construct a new Animation(...) when necessary without requiring a default constructor. If you do this, don't forget to delete it when you are done. An automatic pointer such as std::unique_ptr<Animation> or one of the other smart pointers (boost has some too) can make that easier on you.
you need a default constructor class Animation since you provide parameter constructor ,the compiler would not generate one for you
Animation() {}
I am a beginner in C++ and am trying to learn it by looking at examples.
Here is an example definition for a class that I don't understand the meaning completely:
class MyClass{
public:
std::string name;
void *data;
MyClass(const std::string& t_name, void *t_data) : name(t_name), data(t_data) {}
};
Here is what I understand:
name and *data are variables of the class and, MyClass(...) is the constructor. The meaning of : is the left side class is derived from the right hand side class. However, what is the meaning of this part of the code:
MyClass(const std::string& t_name, void *t_data) : name(t_name), data(t_data) {}
Here are the questions:
what are "t_data" and "t_name"? Are they initial values for "data" and "name"? what is the reason t_ is used here?
what is the meaning of : in the above line?
what is {} at the end of that line?
Thanks for the help.
TJ
what are "t_data" and "t_name"? Are they initial values for "data" and "name"?
They are the arguments passed to the constructor. If an object were created as
MyClass thing("Fred", some_pointer);
then, in the constructor, t_name has the value "Fred" and t_data has the value of some_pointer.
what is the reason t_ is used here?
Some people like to tag the arguments to give them different names to the class members, but there's no need to do that unless you want to.
what is the meaning of : in the above line?
That marks the start of the initialiser list, which initialises the class member variables. The following initialisers, name(t_name), data(t_data) initialise those members with the constructor's arguments.
what is {} at the end of that line?
That's the constructor's body, like a function body. Any code in their will be run after the members have been initialised. In this case, there's nothing else to do, so the body is empty.
It is good C++ practice to use initializer lists to initialize members.
t_name, t_data are the parameter names.
The "t_" prefix is merely used to distinguish it from the similarly named member fields.
The members are being initialized using syntax that resembles a function call, but it is a proper initialization/construction, so you should think of it that way.
The colon signals the beginning of an initializer list
The empty braces {} designate that the body of the constructor (which happens after the members are initialized) is empty.
MyClass(const std::string& t_name, void *t_data) : name(t_name), data(t_data) {}
is constructor of your class, and you should initialize your class with a string and void* parameter, then you initialize your class fields (name and data) with your passed parameters
This is a somewhat compressed example for a beginner, but you're asking good questions.
1) t_data and t_name are the parameters going into the constructor. When you create an instance of this class, you'll do something like:
MyClass * myNewClassInstance = new MyClass("My name", &myData);
Now the constructor has "My name" (in std::string form) as t_name and a pointer to myData as t_data.
2) The colon here does not refer to a derived class. Here it says that an "initializer list" is to follow. Check out Prashant's answer's link, or do a little digging about this. Basically, this is setting the member variable name to t_name (which is the std::string that we passed into the constructor in the above example), and data to t_data (the void pointer). (see additional notes below)
3) The {} is the actual definition of the constructor. It's empty -- there's no code here. So all the constructor will do is initialize the member variables (as defined by the initializer list), and nothing more.
Now let's look at the exact same class in a more beginner-friendly format:
// The declaration of MyClass. This would often show up in a header (.h) file
class MyClass {
public:
// Member variables
std::string name;
void * data;
// Declaration of constructor -- we haven't defined what actually does here, just
// what parameters it takes in.
MyClass(const std::string& t_name, void * t_data);
}
// We declared what the class "looks like" above, but we still have to define what
// the constructor does. This would usually show up in a .cpp file
// This is the constructor definition. We have to specify that it's part of the
// The extra "MyClass::" specifies that it's part of the MyClass namespace that we
// declared above.
MyClass::MyClass(const std::string& t_name, void * t_data)
{
// Set our member variables to what was passed in.
this.name = t_name;
this.data = t_data;
}
The above version does exactly the same thing (with some subtle differences between initializer lists and traditional initialization in the constructor that you probably don't care about yet -- again, see other references regarding this if you're curious).
It's pretty obvious that this takes up a lot more space, and that's exactly why the more compressed format is often used. But when you're just starting out, it makes things a lot more clear doing it this way. It's important to understand the difference between a declaration and a definition when it comes to functions (i.e. the constructor), because the example you posted does both at the same time when often they are separated.
I am a beginner in C++ and am trying to learn it by looking at examples.
For whatever reason, this is harder to do in C++ than it is in Perl, Python, Java, or even C. I don't recommend this course; instead, you might invest in a good book.
Here is what I understand:
Let's start with that. I don't think you understand as much as you claim to.
name and *data are variables of the class
No. name and data are variables of the class. Their types are std::string and void*, respectively.
MyClass(...) is the constructor.
Yes.
The meaning of : is the left side class is derived from the right hand side class.
No, : means different things in different contexts. In the context in which it is used in your sample, it indicates that an initializer list follows.
However, what is the meaning of this part of the code:
what are "t_data" and "t_name"?
They are local variables in the constructor function. Specifically, they are the passed-in parameters to the function.
Are they initial values for "data" and "name"?
That is how they are being used in this sample. Specifically, they are being passed to the data and name initializers in the initializer list.
what is the reason t_ is used here?
This is purely the convention of this particular author. I've never seen that convention before.
what is the meaning of : in the above line?
It introduces an initializer list. This construct is only used in constructor member functions. Each named member is initialized by the values listed. (Note: the values do not need to come from parameters -- they can be any legal expression, so: MyClass(int ii) : i(ii), j(cos(0) / 2), k(&global_variable) {} might be a legitmate constructor. )
what is {} at the end of that line?
The body of the constructor member function. Since all of the work of the constructor is being done in the initializer list, the body of the function is empty.
Please help me with the following problem:
I have the following classes:
class ChemicalElement
{
private:
std::string _name;
void Init(const std::string& name);
public:
ChemicalElement(const std::string& name);
ChemicalElement(const ChemicalElement& ce);
};
class CombinationRule
{
private:
ChemicalElement _ce1;
ChemicalElement _ce2;
void Init(const ChemicalElement& ce1, const ChemicalElement& ce2);
public:
CombinationRule(const ChemicalElement& ce1, const ChemicalElement& ce2);
CombinationRule(const CombinationRule& rule);
};
The implementation is obvious. I intended to initialize the CombinationRule using the Init method to minimize code duplication. Alas, if I do not use "member initialization list" in each constructor the compiler complains with "error C2512: 'ChemicalElement' : no appropriate default constructor available". Is there an elegant way to solve this error instead of using a default constructor or member initialization list?
BTW: if there are any other problems in the classes definition please add it too. Since I'm revisiting C++ I want to be aware of them.
You should implement constructors of CombinationRule as follows so they will use appropriate constructors of ChemicalElement:
CombinationRule::CombinationRule(const ChemicalElement& ce1,
const ChemicalElement& ce2) : _ce1(ce1), _ce2(ce2)
{
...
}
CombinationRule::CombinationRule(const CombinationRule& rule) :
_ce1( rule._ce1 ), _ce2( rule._ce2 )
{
...
}
I think you are required to put a default constructor in any class where you define any other constructors, if you want to use objects of that class in any kind of array or container. The default constructor's implementation can just be an empty/no-op method though.
You shouldn't need to put in a member initialization list (although using a member initialization list can be more efficient in some cases, since that way your member variables are only initialized once, instead of being initialized once via their default constructor, and then written to a second time by your Init() method)
I think you want this
ChemicalElement * ce1;
I say this because I think its trying to run the default constructor on your CombinationRule and in turn needs to get a ChemicalElement for ce1 and ce2 ... but I could be wrong.
Pretty sure Krill's way is the way to specify the constructor of a variable for a specific constructor BUT i said f that and just made it so ce1 doesn't need to be constructed by the compiler :)
In this particular example I would go on with duplication (it's just writing two initializers, nothing to get obsessive about).
But assuming the real story is more complex: use OO facilities to avoid code duplication.
class CombinationRule : public ElementPair ...
or
class Combination { ElementPair twoElements; ...}
Where ElementPair contains two ChemicalElements and a single constructor (with common code), and Combination rule constructors initialize using constructor of ElementPair.
There are other approaches: initializing members with some InvalidChemicalElement instance or using pointers (auto_ptr) with NULL for InvalidChemicalElement.