I have a singleton class for which I need a private member. I want that member to be empty until I use my setter method to set the right data.
class PlaybackHelper{
private:
PlaybackHelper();
PlaybackHelper(PlaybackHelper const&);
void operator=(PlaybackHelper const&);
playback_type type;
Note note;
public:
void setPlaybackType(playback_type aType);
static PlaybackHelper &getInstance();
};
Xcode is giving me an error in my implementation file (where I'm implementing my private constructor) saying that I should initialize my member:
PlaybackHelper::PlaybackHelper(){
}
error: Semantic Issue: Constructor for 'PlaybackHelper' must explicitly initialize the member 'note' which does not have a default constructor
I don't understand why I'm not able to do this (especially since it's not giving me any errors for the playback_type type; (enum) member which works the same way) Any ideas what I could do to leave my Note member empty until I'm ready to assign a value to it?
playback_type is a plain old data, thus lacking of initializing type simply leaves it as uninitialized; However, class Note's non-default constructor is defined, and thus its default constructor would not be generated automatically if you did not define it.
To solve it, you could either
initialize it with the parameters of (one of the) non-default constructors defined by you.
PlaybackHelper::PlaybackHelper() : note(/*...*/)
{
}
Define a default constructor for class Note
The error message is clear - there's no default constructor for Note. Either create one, or initialize Note in the initializer list with an existing constructor.
I want that member to be empty until I use my setter method to set the right data.
You can't. Both note and playback_type exist when you create your object.
Since Note doesn't have default constructor (i.e parameterless constructor), you have to initialize it in the member initialization list as:
PlaybackHelper::PlaybackHelper() : note(/*..args...*/)
{ //^^^^^^^^^^^^^^^^^^^^member initialization
}
Pass the appropriate argument(s) to note as required by Note constructor. You've to do the same, for other constructor of PlaybackHelper a well.
Related
I apologize in advance because some of my verbiage may not be 100% correct.
I will have a class like this:
class ClassName {
private:
AnotherClass class2;
public:
ClassName();
~ClassName();
...
In the constructor of this class, among other things, I put the line
ClassName::ClassName() {
AnotherClass class2;
}
Which is how I thought you were supposed to initialize objects in C++, however I was noticing (through GDB) that two AnotherClass objects were being created. Once on the Constructor definition then again on my initialization line. What is the reasoning behind this? What if I wanted to use a more complicated constructor like AnotherClass(int a, int b), would it create a temporary object then create the correct one shortly after?
AnotherClass class2; creates another local object inside the constructor body, that gets destroyed at the end of the body. That is not how class members are initialized.
Class members are initialized before the constructor body in the member initializer list between the constructor signature and body, starting with a :, like so:
ClassName::ClassName() :
class2(argumentsToPassToClass2Constructor),
anotherMember(42) // just for example
{
/* constructor body, usually empty */
}
If you don't want to pass any arguments to the class2 constructor you don't have to put it in the initializer list. Then its default constructor will be called.
If you simply want to call the default constructor on all of your class members, you can (and should) omit the constructor altogether. The implicitly generated default constructor will do just what you wanted.
What you are doing in your constructor is creating another variable, local only inside the constructor.
Actually, if you do nothing, the default constructor in AnotherClass will be called for the class2 object.
If you want to be explicit, you can use a constructor initializer list:
ClassName::ClassName()
: class2()
{
}
This last method is also the way you call a specific constructor with arguments in AnotherClass, if you need to do that.
ClassName::ClassName() {
AnotherClass class2; // this will create local variable only
}
If AnotherClass will have default constructor, then it will be called for the class2 object by compiler.
If you want to call parametrized constructor then you will have do it in following way:
ClassName::ClassName() :
class2(arguments)
Why to use and How to use initializer list :
Consider the following example:
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Here compiler follows following steps to create an object of type MyClass
Type’s constructor is called first for “a”.
The assignment operator of “Type” is called inside body of MyClass() constructor to assign
variable = a;
And then finally destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with MyClass() constructor with Initializer List
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
With the Initializer List, following steps are followed by compiler:
Copy constructor of “Type” class is called to initialize : variable(a). The arguments in initializer list are used to copy construct “variable” directly.
Destructor of “Type” is called for “a” since it goes out of scope.
As we can see from this example if we use assignment inside constructor body there are three function calls: constructor + destructor + one addition assignment operator call. And if we use Initializer List there are only two function calls: copy constructor + destructor call.
This assignment penalty will be much more in “real” applications where there will be many such variables.
Few more scenarios, where you will have to use initializer list only:
Parametrized constructor of base class can only be called using Initializer List.
For initialization of reference members
For initialization of non-static const data members
You are just creating a local variable in this line. In general there are three ways of initializing private members:
Default initialization
If you do nothing on your constructor, the compiler will automatically initialize the private member by calling its default constructor (ctr without parameters)
Assigning them to a value in the ctr body
In this case you have to assign the desired value to your private member by using the assignment operator.
ClassName::ClassName()
{
class2 = AnotherClass(a, b, c); // if the class ctr has some parameters
}
By using the initialization list
In your case it will be something like:
ClassName::ClassName()
: class2(initial_value)
{
}
This is in general the best and efficient option for initializing your class private members since you avoid calling the copy constructor for the passed parameters. This is in general is not an issue unless the copy ctr contains time-consuming operations. The same apply for the option #2 in this case you may have the same issues with the assignment operator
What you did there is to create a new variable with the same name as you member,
By doing this you overshadowed your member variable.
Also, in the process your member constructor was silently called in the ClassName empty initialisation list.
you can initiate the class in two ways:
ClassName::ClassName(): class2() {}
or:
ClassName::ClassName() {
this->class2 = AnotherClass();
}
The first way is better and a must some times.
If you only use empty constructors for your members you won't see the difference, except in performance, because the compiler initialize the member by default in its initialisation list ( the part after the ":", if you don't do that, he does it silently for you... )
But if your member doesn't have an empty constructor, for example:
AnotherClass:: AnotherClass(int a, int b)
if you will try to use the second way on initialisation you will get a message like:
error: constructor for 'Initiator' must explicitly initialize the member 'class2' which does not have a default constructor
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 writing the following classes in C++.
class SImage {
...
public:
SImage(char*);
}
class SImageProc {
SImage S;
...
public:
SImageProc(SImage Im) { S = Im; };
}
When compiling I receive this referencing the line where I implement my constructor:
SImageProc.cpp:5:33: error: no matching function for call to 'SImage::SImage()'
I cannot figure out why it is interpreting my parameters as instantions of a class when implementing the SImageProc class.
SImage does not have a default constructor, because you have provided constructor SImage(char*). This means the compiler no longer provides a default one. Something elsewhere in your code requires SImage, causing the error.
You need to provide a default constructor for SImage, or remove the code that requires it. It is not possible to say which one of the solutions is suitable without more details.
My wild guess would be that SImageProc has an SImage data member, and you are not initializing it in the constructor initialization list. This is how you would fix that problem:
SImageProc(SImage Im) : S(Im) {};
The explanation for that is that, by the time you reach a constructor's body, all data members and bases have been initialized. After initialization you can only modify them (in your example, you were assigning to S.) If you do not explicitly initialize data members and bases in the constructor initialization list, they (usually) get default initialized, which in the case of a user defined type means the default constructor is called. This is the source of the error.
In the header, I'm defining bool isActive. In classes derived from this one, I would like to make isActive false by default. I tried doing this by adding
AbstractClass::isActive = false;
to the cpp file, but that causes the error "Expected constructor, destructor, or type conversion before '=' token."
Initialize it in the class' constructor:
class AbstractClass {
bool isActive;
AbstractClass() : isActive(false) {
}
// ...
};
That the class contains abstract methods doesn't stop it from having a constructor that is used to initialize its member variables.
AbstractClass::isActive = false;
refers to a (non-existent) static class member. If that existed, it would exist as a single shared instance for the entire class, and you would in fact initialize it as you did.
But you have an instance variable, which means that every instance of the class has its own copy. To initialize that, you'd do what sth say; initialize it in the class's ctor, either in the ctor body or better, as sth suggests, in the initializer list.
I have a struct that's defined with a large number of vanilla char* pointers, but also an object member. When I try to statically initialize such a struct, I get a compiler error.
typedef struct
{
const char* pszA;
// ... snip ...
const char* pszZ;
SomeObject obj;
} example_struct;
// I only want to assign the first few members, the rest should be default
example_struct ex = { "a", "b" };
SomeObject has a public default constructor with no arguments, so I didn't think this would be a problem. But when I try to compile this (using VS), I get the following error:
error C2248: 'SomeObject::SomeObject' : cannot access private member declared in class 'SomeObject'
Any idea why?
Update: Here's the definition of SomeObject
class SomeObject
{
void operator=(const SomeObject&);
SomeObject(const SomeObject&);
public:
SomeObject()
{
// etc
}
// members snipped
}
Your initialization of ex performs copy-initialization. It takes the value on the right and uses it to initialize the variable on the left. For class-type members, the appropriate constructor is used. In your case, that means invoking the copy constructor for SomeObject, but you've made that constructor private, so the compiler is correct in telling you that SomeObject::SomeObject is a private member that can't be accessed.
Although the compiler is allowed to elide the call to the copy constructor and initialize ex.obj directly with the default constructor, that is an optional optimization; it still needs to be allowed to call the copy constructor.
You can either give example_struct a constructor of your own and use that in place of brace initialization, or you can publicize SomeObject's copy constructor.
The rest of the members will be initialized to '0', not "default", right? So it's probably trying to call SomeObject(0), which I'd guess is resolving to a private copy constructor.
It looks like the constructor for SomeObject is private.