I have a member of class A in my own class which constructor takes multiple parameters. Im forwarding parameters of my own class to the constructor of class A. But its important that these parameters are correct, so i need to check them before consructing the member of A. And heres the problem:
I could leave out the member in the member intialization list, effectively calling the default constructor. After the checks in the constructor i could then call A`s constructor in a assigment. Although, this produces a error since the destructor of A is private.
How do i solve this?
MyClass::MyClass(int someParam) : otherMember(2){
//checks for someParam
member = A(someParam); // <- produces error
}
You're going to need an accessible destructor no matter what you do. But to address your question, one option would be to call a static function to check parameters from within the initializer:
class MyClass {
private:
static void checkParam(int);
// ...
};
MyClass::MyClass(int someParam) : otherMember( (checkParam(someParam), 2) ) {
// ...
}
static void MyClass::checkParam(int someParam) {
if (...) throw someException();
}
Note that the , used there is the comma operator, not an argument separator - it evaluates both left and right expressions, and throws away the result of the left.
I see two ways of approaching this:
Make sure class A can be used with a parameter-less constructor, and set someParam in a separate method: A.SetSomeParam(someParam)
Not inherit from A, but rather hold a member object of type A, and then you can construct it whenever you like.
Related
I wrote a class that holds an array of objects, which each expect a pointer to a c-struct in their constructor:
Here's some code:
class TheOtherClass
{
private:
SomeCStruct* m_pCStruct;
int m_ObjIdx;
public:
TheOtherClass::TheOtherClass(SomeCStruct* pCStruct, int ClassIdx)
: m_pCStruct(pCStruct),
m_ObjIdx(ClassIdx)
{}
}
class MyClass
{
private:
TheOtherClass m_objects[4];
SomeCStruct* m_pMyCStruct;
public:
MyClass::MyClass(SomeCStruct* pCStruct)
: m_pMyCStruct(pCStruct)
{
m_objects[4] = {TheOtherClass(&pCStruct, 1), TheOtherClass(&pCStruct, 2),
TheOtherClass(&pCStruct,3), TheOtherClass(&pCStruct, 4)};
}
I'd actually like to initialize the member objects of MyClass in the init list of the constructor but I was reading this isn't possible?
Hence I tried the above approach but I'm always getting the error: "TheOtherClass": no appropriate default constructor available.
Another thing to mention is that the compiler I'm running is a state of the art C++03 compiler ;-) (it's code for a DSP and TI sort of doesn't wants to update the compiler)
Any help would be highly appreciated!
Since MyClass(SomeCStruct* pCStruct) constructor doesn't (can't) initialize the TheOtherClass m_objects in the member initializer list, the m_objects will need to be default constructed at first, and then this member will be reassigned with new value in the body of the MyClass constructor.
The TheOtherClass won't have a synthesized constructor since you have defined (other, non-default) ctor that takes SomeCStruct* and int. Thus, no default constructor for it in your code.
Here, we define a default constructor:
class TheOtherClass {
SomeCStruct* m_pCStruct;
int m_ObjIdx;
public:
TheOtherClass() : m_pCStruct(nullptr), m_ObjIdx(0) {} // Default ctor
TheOtherClass(SomeCStruct* pCStruct, int ClassIdx)
: m_pCStruct(pCStruct),
m_ObjIdx(ClassIdx) {}
};
As to the MyClass. Since you've already pass the argument as a pointer MyClass(SomeCStruct* pCStruct), you don't need to take the address of it (as in &pCStruct).
And the main issue in the MyClass is that the m_objects is of class type TheOtherClass which does not define any operator=, including the one that takes brace-enclosed initializer list. So, you won't be able to do like so:
m_objects[4] = { // The operator '=' has not been defined for the TheOtherClass, also note the subscript
TheOtherClass(pCStruct, 1),
TheOtherClass(pCStruct, 2),
TheOtherClass(pCStruct,3),
TheOtherClass(pCStruct, 4)
};
Again, when you try to list initialize it, it has already been default constructed. Thus, for this approach to work you will need to define such copy-assignment operator to do this kind of assignment to an already default constructed instance of the TheOtherClass. As to how to implement this operator, it will mostly depend on the overall design and other factors which were not mentioned in this thread.
Update
If you will have the following body of the MyClass constructor, it will work:
MyClass(SomeCStruct* pCStruct) : m_pMyCStruct(pCStruct) {
// Assign to default initialized TheOtherClass object
m_objects[0] = TheOtherClass(pCStruct, 1);
}
I would advise you to check these:
Operator overloading
Constructors and member initializer lists
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
Can one overload a constructor with a private constructor with the same parameters?
Basically if something stores a positive integer, then in the public constructor it would make sure a positive integer was being stored, whereas in a private constructor it doesn't perform the check.
Obviously this example isn't really an appropriate use, but sometimes you want to create an object inside a method and you don't want it to waste time performing full safe initialisation; you may want to just tell it to create something straight away without the special checks (or more prudently heap allocations or something expensive) when you're going to perform them again later or they're just unnecessary, and a method inside the class should be able to use this constructor automatically instead of the other public one with the same parameters.
You cannot overload on acccess like private versus public, but you can overload on the signature: the number of arguments and their types.
Private constructors are quite common.
One usage is for a logically "deleted" constructor (finally directly supported by C++11), and another is for use by a public factory function.
Example:
class A
{
public:
A( int const x)
{
// Whatever, checked construction.
// Perform the check of the x argument.
// Then other things.
// In C++11 it can be done by checking x and forwarding to the
// unchecked constructor in the same class. Not shown here though.
}
private:
enum unchecked_t { unchecked };
A( int const x, unchecked_t )
{
// Unchecked construction.
}
// Methods that possibly use the unchecked constructor.
};
No, you cannot overload a public constructor or another member function with a private one: only the name and the parameter types count for the purpose of overload resolution.
To do what you are looking for, define a private constructor that takes an additional bool parameter that indicates that the parameter checking needs to be performed:
class A {
public:
A(int x) : A(x, true) {}
private:
A(int x, bool check) {
if (check) {
// Perform the check of the x argument
}
}
};
To construct an instance and bypass the check, functions that have access to the private constructor call
A aUnchecked(-123, false);
Checked instances constructed the usual way:
A aChecked(123);
with a private constructor you cant instantiate a class directrly instead you used something called named Constructor Idiom.
other thing you cant inherit the class since the class which wants to inherit will not be able to access the constructor
what you should do is to craete w amethode which is called from the constructor to check
So I have searched all over the place and I can not seem to find the answer to this specific question. I am using a winXP with cygwin and gcc 3.4.4 cygming special.
Problem:
I have a class that works as an interface with some abstract methods and protected variables that should be in every class that inherits from this class. Now I also have another class that is a member variable of this interface.
class Bar {
private:
int y;
public:
Bar(int why);
};
Bar::Bar(int why) : y(why) {}
class Foo {
protected:
Bar b;
public:
Foo(int x);
virtual void print_base();
};
Foo::Foo(int x) : b(x+3) // Have to use initializer list here.
{
//this->b(x+3); // doesn't work
}
class DerFoo : public Foo {
protected:
Bar db;
public:
DerFoo(int x);
};
DerFoo::DerFoo(int x) : Foo(x),
db(x+3) // (Bar)(int) being called, works fine
// db(4.0, 30) // no matching function for call to Bar::Bar(double, int)
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) // doesn't work class DerFoo does not have any field named 'b'
{
//this->b(x - 3); // Doesn't work, error no match for call to (Bar)(int)
//this->db(x + 3); // Doesn't work, error no match for call to (Bar)(int)
}
So the problem as you can see is inside the derived foo class, DerFoo how to initialize b. I have tried member initialization method, but then the compiler doesn't realize about protected variables. So then for some bizarre reason unbeknownst to me, it can not find the constructor in this class. Even though if were to include a "wrong" call to the constructor of a protected member variable (non inherited) it would suggest the correct version of the constructor.
I have no clue still how to do this. Any help is greatly appreciated.
After you declare a variable you have to set it otherwise you will be calling it like a function.
this->b = Bar(x+3);
The preferred way is to use the initializer list to avoid unnecessary copies of Bar. If you do, however, need to set b outside of the constructor the above example is how to do so.
DerFoo's constructors must not (and cannot) initialize b, that's Foo job. DerFoo's constructors are responsible for initializing only DerFoo's immediate subobjects, namely db and the Foo which is a base class of DerFoo. Foo's constructor, in turn, is responsible for initializing b.
The sequence of events is like:
DerFoo's constructor invokes Foo's constructor
Foo's constructor invokes b's constructor
Foo's constructor runs its body, leaving the Foo object completely constructed
DerFoo's constructor invoke's db's constructor
DerFoo's constructor runs its body, leaving the DerFoo object completely constructed.
If, in the DerFoo constructor, you don't like the value that the Foo constructor left in b, you can assign a new value to b, using any one of these syntaxes:
b = Bar(47);
this->b = Bar(47);
this->Foo::b = Bar(47);
Foo::b = Bar(47);
I don't find the question very clear, but let's see if I understood what you are trying to do and how.
DerFoo::DerFoo(int x) : Foo(x), [a]
db(x+3)
// db(4.0,30) [1]
// note: candidates are Bar::Bar(const Bar&), Bar::Bar(int)
// b(x-3) [2]
{
//this->b(x - 3); [3]
//this->db(x + 3); [4]
}
The first error is [1], where the compiler is telling you that there is no constructor of Bar that takes both a double and an int. The error also lists the two possible constructors that you can use: Bar(int), Bar(Bar const &). I am unsure as of what you intended with this line, but you have already figured out (previous line) that by just providing an int the call will work.
[2] b is not a member of DerFoo, and thus cannot be initialized in the initializer list of DerFoo. It is the responsibility of Foo to initialize it's own member and that will happen through the call to the Foo constructor in [a].
[3],[4], both expressions take the form this->member(i). During initialization the syntax member(i) will well, initialize member with the value of i. Outside of initialization the syntax means call operator()( int ) passing the value of i. Those members have already been initialized, but if you want to reset them you need to assign rather than initialize them.
b is inside the Foo class. to access it (for sure) use
Foo::b = Bar(x-3);
You don't have to use an initializer list, you definitely also should use an initializer list at this point.
At construction of an object, before the code of the constructor is entered all member variable are already constructed. If you don't give initializers, they will be default constructed.
Also you cannot construct a variable again, after it already has been constructed. Your
this->b(x+3)
is not telling the compile to construct b it is telling it to call a function named b on your object. Such a function does not exist in your class, hence the error. Note that once an object has been constructed into a variable, there is no way, to ever call the constructor for that variable again (only to change the value).
A value can be changed using = as in most languages. Hence you could do:
Foo::Foo(int x)
{
this->b = Bar(x+3);
}
This means you are creating another nameless Bar object and assigning it's value to this->b. You should be aware, that this means, you will create two Bar objects, when creating a Foo. First the default constructed one, before. The constructor code is entered, then the new nameless one. Then you will finally assign the value to the already constructed object, so this code is much more inefficient than the one, which uses initializer lists.
EDIT:
Since I missed the second doesn't work in the code above here some additional information:
You are also trying to initialize b directly in the constructor of the derived DerFoo object. However once this part of code is reached, it has already been constructed. Hence any attempt to construct it in the derived constructor comes to late.
Hence you either have to add another constructor to Foo which takes the value and use that one in your constructor of DerFoo. This solution is preferable, since it will only construct the Bar object in b once. If you cannot add such a constructor, then you need to use an assignment in the constructor code for DerFoo.
Trying to initialize b directly in the DerFoo constructor will not work even if the scoping operator is used.
DerFoo::DerFoo() : Foo::b(x-3) {}
will still produce an error: http://ideone.com/6H8ZD
I know this as this will assign the constructor parameter to the class member:
class A
{
public:
some_type B;
A(some_type B)
{
this->B = B;
}
}
But what will this do:
class A
{
public:
some_type B;
A(some_type B) : B(B)
{
}
}
Will this assign the parameter to itself or the parameter to the class member or do something else?
How are the names in the list after construct thing (I have no idea how its called) resolved?
That Thing is called a Member Initializer List in C++.
There is a difference between Initializing a member using initializer list(2nd Example) and assigning it an value inside the constructor body(1st Example).
When you initialize fields via initializer list the constructors will be called once. The object gets constructed with the passed parameters.
If you use the assignment then the fields will be first initialized with default constructors and then reassigned (via assignment operator) with actual values.
As you see there is an additional overhead of creation & assignment in the latter, which might be considerable for user defined classes.
How are the names in the list after construct thing (I have no idea how its called) resolved?
public:
some_type B;
A(some_type B) : B(B)
{
}
In the above snipet, there are two entities named B:
First is the one that constructor receives as an argument &
Second is the member of the class A
The variable received as argument in Constructor of A gets passed as an argument for constructing B(by calling its constructor) which is member of class A. There is no ambiguity in names here, the all to constructor is:
this->B(B);
this is class A pointer.
B() is constructor of type B.
B inside the parenthesis is an instance of type B.
Will this assign the parameter to itself or the parameter to the class
member or do something else?
It will assign the parameter to the class member.
How are the names in the list after construct thing (I have no idea
how its called) resolved?
This is the initializers list, and though the example can lead to confusion, the id at the left of the parenthesis is a member of the class, while the id (or literal) inside the parenthesis can only be one of the parameters of the constructor: thought that way, there is no ambiguity at all.
The key here is that this list must initialize class members with some value, so if you think of
...: B(B)
as conceptually equivalent to a constructor call:
this->B(B)
... there is no ambiguity.
In the first situation, your objet will be constructed. In the second, it will be constructed (with default constructor) and assigned.
You might not want assignation (maybe the operator is not defined, or no default constructur or the behaviour is specific, or maybe, in some cases because of performance issues).
Concerning the visibility, in both cases, if you just use B, it's the parameter you're manipulating.