I need to delay the constructor call, so I can initialize the value that should be passed to the constructor. I have written a short and very simplified example.
class A
{
private:
ObjectA* _ptr;
public:
A(ObjectA*);
};
class B
{
private:
A object; // The constructor seems to be called here?
ObjectA* obj;
public:
B();
};
A::A(ObjectA* ptr)
{
this->_ptr = ptr;
}
B::B()
{
obj = new ObjectA();
object(obj); // I want to call the 'A' constructor here, after initializing of 'obj'.
}
Is it possible?
No, you cannot defer a construction of a value member. You can use a pointer instead of a direct value but that's no solution for your problem.
The proper solution for your problem is using initialization list:
B::B ( ) : obj(new ObjectA), object(obj) {}
Also, you have to put obj before object in class B:
class B
{
private:
ObjectA *obj;
A object;
public:
B ( );
}
The reason for this is that, when a constructor is called, all of the objects members must be properly constructed and initialized. This is done using their default constructor.
The reason for reordering the class members is that the initializers of the members are called in the order they are declared in the class not in the order of their appearence in the initialization list.
Here is a solution I would use.
class B
{
private:
char m_aBytes[sizeof(A)];
A& getA () { return *(A*)m_aBytes; }
public:
B ()
{
ObjectA* objA = new ObjectA ();
new (m_aBytes) (objA);
}
}
Related
I have the following sample code
class ClassB {
public:
ClassB(int i); // No default constructor
}
class ClassA {
ClassB obj; //NOT a pointer
public
ClassA() {
//calculate someInt;
obj = ClassB(someInt); // doesnt work
}
}
How do I initialize obj?
The compiler complains about no appropriate default constructor available for obj
The best design solution for you would be to initialize member obj in the initialization list like this:
ClassA() : obj(someInt) { }
However, another option for you would be to declare the default constructor for ClassB like this:
ClassB() {}
or simply let the compiler create the one for you by using this:
ClassB() = default;
From C++ Standard this is:
defaulted default constructor: the compiler will define the implicit
default constructor even if other constructors are present.
If you go for a second option, then the following code would pass without the error:
#include <iostream>
class ClassB {
public:
ClassB() = default;
ClassB(int i);
};
class ClassA {
ClassB obj;
public:
ClassA() {
int someInt = 0;
obj = ClassB(someInt);
}
};
int main() {
return 0;
}
Check it out live
Conclusion
I would deeply recommend using the first option, the one with the initialization list because it is not needed to default construct objects before and then assigning to them. Also, this is the only option for objects that don't have an assignment operator.
UPDATE 1
One more way around this problem is using the std::shared_ptr<ClassB> obj in your ClassA as follows:
#include <iostream>
#include <memory>
class ClassB {
public:
ClassB(int i);
};
class ClassA {
std::shared_ptr<ClassB> obj;
public:
ClassA() {
int someInt = 0;
obj = std::make_shared<ClassB>(someInt);
}
};
int main() {
return 0;
}
UPDATE 2
One more possibility that came up to my mind is to calculate integer in a separate function and the just call it as part of the initialization list like in the following code:
#include <iostream>
class ClassB {
public:
ClassB(int i);
};
class ClassA {
ClassB obj;
public:
ClassA()
: obj(calculate())
{}
private:
int calculate() {
return 1;
}
};
int main() {
return 0;
}
Check it out live
You initialize members in the constructor initialization list. Like so:
ClassA() : obj(someInt) { }
I have a class B which has a member that is a pointer to an object of a A class. When using copy constructor on an object of type A, it is copied but the member variable is not.
Is there any way to copy an A object and to automatically make a copy of its B member?
The following code shows the problem I'm triying to explain:
class A
{
public:
A(char t_name)
{
name = t_name;
}
~A()
{
}
char name;
};
class B
{
public:
A* attribute;
B()
{
attribute = new A('1');
}
~B()
{}
};
int main()
{
B* b_variable = new B;
B* b_copy = new B(*b_variable);
return 0;
}
When using copy constructor on an object of type A, it is copied but the member variable is not.
Your code never calls any copy constructor in class A.
Your code calls a copy constructor in class B and it does exactly what is is supposed to, i.e. copies the value of attribute which is a pointer to a class A object.
In other words - after executing your code, you have two instances of class B and one class A instance. In the two class B instances attribute points to the same class A instance.
This is (most likely) not what you want.
As many already has pointed out (e.g. see #lostbard answer), you'll need a copy constructor in class B to do a deep-copy. A deep-copy is needed because class B have a pointer member.
Also you should do some clean up in class B destructor and in main.
#include <iostream>
using namespace std;
class A
{
public:
A(char t_name)
{
name = t_name;
}
~A()
{
}
char name;
};
class B
{
public:
A* attribute;
B()
{
attribute = new A('1');
}
/** Copy constructor */
B(const B ©)
{
// Make a new instance of class A
attribute = new A(*copy.attribute);
}
/** Assignment operator */
B& operator= (const B& other)
{
// Delete the existing class A instance
delete attribute;
// and create a new as a copy of other.attribute
attribute = new A(*other.attribute);
}
~B()
{
// Delete the class A instance
delete attribute;
}
};
int main()
{
B* b_variable = new B;
B* b_copy = new B(*b_variable);
// Delete the two class B instances
delete b_variable;
delete b_copy;
return 0;
}
There is no need for a copy constructor in class A. The default generated will do as Class A has no pointer members.
EDIT
As pointed out by #Slava you should always implement a assignment operator when you make a copy constructor (rule of three) so I added it to the code above.
Some like the rule of three to be the rule of five so it also include move. Read more here: https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
While there are many solutions, I'd bet sooner-or-later you'll end up with implementing the usual virtual a.clone();. That works flawless when you'll have derived classes of A (which is more-or-less the only legitimate reason why you're keeping A as a pointer to a heap-allocated object and not as a value member :) ).
Note that, when you're implementing clone() in your hierarchy, that C++ supports covariant pointer return types. Thus, if base has a virtual that returns e.g. Clonable*, then A's same method can return A* and A's descendant ADerived can return ADerived*. Feel free to understand 'can' as 'should' for the case of clone().
Create a copy constructor for A and for B:
class A
{
public:
A(char t_name)
{
name = t_name;
}
A(const A& copy)
{
name = copy.name;
}
~A()
{
}
char name;
};
class B
{
public:
A* attribute;
B()
{
attribute = new A('1');
}
B(const B ©)
{
attribute = new A(*copy.attribute);
}
~B()
{}
};
I have a question about default constructor on inherited class when the parent one is protected, in my mind the child class will have a default one protected too, but it's not the case.
Is there's a way to force the default constructor to be protected other than force it on child class ?
C++11 - gcc version 5.3.1 20151219 (Debian 5.3.1-4).
int main ( int argc, char ** argv )
{
using namespace std;
class A
{
public:
static std::shared_ptr<A> CreateInstance ()
{
A * pInstance { new A };
return { pInstance, []( A * pInstance )
{
delete pInstance;
}};
};
protected:
A () = default;
~A () = default;
};
class B : public A
{
};
B b; // It's work !
return 0;
}
Thanks for your help,
WCdr
No, a derived class' automatically-generated default constructor will still be public even if the base class constructor is protected.
There are two ways (I can think of) to prevent derived class B from being directly instantiable:
1. Remove the default constructor in class A
This can be accomplished by providing a constructor that takes a dummy argument:
class A
{
public:
// ...
protected:
A (int) {}
};
class B : public A
{
};
B b; // error: B::B()' is implicitly deleted because the
// default definition would be ill-formed
Instantiating B will fail, because B's automatically-generated default constructor will attempt to use A's default constructor, which does not exist.
But this is easily circumvented:
class B : public A
{
public:
B() : A(0) {}
}
B b; // works
2. Force the derived class' constructor to be protected
class B
{
// ...
protected:
B() = default;
}
Option (2) will be the least surprising to others reading your code, and is the option that I recommend. Anyone familiar with static createFoo factory functions will understand why the constructor is made private or protected.
EDIT
When using static create factory functions in a class hierarchy, the common idiom is for derived classes to also provide static create factory functions, and make their constructor private or protected.
Derived classes should not use the create factory function of the base class. They should invoke base class constructor, either implicitly or explicitly.
class Base
{
public:
static shared_ptr<Base> create()
{
return shared_ptr<Base>(new Base);
}
protected:
Base() {...}
};
class Derived
{
public:
static shared_ptr<Derived> create()
{
return shared_ptr<Derived>(new Derived);
}
protected:
Derived() {...} // Implicitly calls base class default constructor
};
// Usage
auto b = Base::create();
auto d = Derived::create();
I've two classes called FWindow and FFramwWindow. The FFramwWindow class inherits the FWindow. The FWindow class contains two constructor method.
The first one is default constructor and the second one contains one parameter of int type.
I call the second constructor from the FFramwWindow class default constructor to initialize a member variable of the FWindow class called 'value'.
But I don't know why it isn't working -
class FWindow {
public:
int value;
FWindow()
{
this->value = 0;
}
FWindow(int val)
{
this->value = val;
}
};
class FFramwWindow : public FWindow
{
public:
FFramwWindow()
{
FWindow::FWindow(6);
printf("value %d\n", this->value);
}
};
int main(int argc, _TCHAR* argv[])
{
FFramwWindow obj;
return 0;
}
The above code prints - value 0
Where I expected it will print - value 6
Seems it's only calling the default base class constructor, not the second one that I called explicitly.
Note: I'm using Visual Studio 2008
Because you should do the following in constructor:
FFramwWindow() : FWindow(6)
{
....
In your original code you create a local (in constructor scope) object of FWindow.
the code
FWindow::FWindow(6);
is not a call to the parent constructor, but the creation of a local instance of FWindow. The correct syntax in C++ to specify which FWindow constructor should be called is
FFramwWindow() : FWindow(6)
{
...
}
If you do not specify the constructor to use for the base class (and for data members), C++ uses the default constructor, that is
FFramwWindow()
{
...
}
is equivalent to
FFramwWindow() : FWindow()
{
...
}
Note that if you have multiple inheritance you should constructors for each base class separating them with comma. As bonus information, the base constructors are called in the order specified in the inheritance definition, not those in which you specify them in the constructor:
class A {
A();
A(int n);
A(string s);
};
class B {
B(int n = 6);
}
class C {
C();
C(float x);
}
class D: public A, public B, public C {
D();
}
D::D() : C(3),A(5)
{
}
In this example, creating an instance of D will invoke in order the constructors for A(5), B(6), C(3.0), D()
You must call the constructor function of the base class when you declare the derived class's constructor. Consider this example:
#include<iostream>
class base
{
public:
int i;
base()
{
i = 0;
}
base(int p)
{
i = p;
}
};
class derived1: public base
{
public:
derived1():base()
{
std::cout<<i<<std::endl; //i is 0 here
}
};
class derived2: public base
{
public:
derived2():base(10)
{
std::cout<<i<<std::endl; //i is 10 here
}
};
class derived3: public base
{
public:
derived3(int x):base(x)
{
std::cout<<i<<std::endl;
//this takes an argument from the derived class's constructor
//as base class's constructor's parameter
}
};
int main()
{
derived1 d1;
derived2 d2;
derived3 d3(9);
return 0;
}
In derived1 class, the first constructor of the base class is called. In derived2 class, the second constructor is called. And in third case, the constructor function takes an argument which is passed to the base class's constructor (That means we are using the second constructor of base class).
In your code,You didn't call the base class's constructor which by default calls the constructor that takes no argument. That's why it is outputting 0.
FWindow::FWindow(6);
This statement just creates a temporary new object of class FWindow which is destroyed right after this statement is executed. Constructor functions are meant to be called automatically when you create a object. They are not meant to be called manually.
You can find some explanation here: http://www.geeksforgeeks.org/possible-call-constructor-destructor-explicitly/
let's say I have a class
class MyClass {
public:
AnotherClass myObject;
};
My issue is that I want to initialize myObject with arguments to it's constructor, exactly if I were declaring it on the stack during a function
AnotherClass myObject(1, 2, 3);
but I want to do this for the class member in the constructor:
MyClass::MyClass() {
myObject = ...?
...
}
The problem is exactly that. If I declare a class member that has a constructor, will C++ call the default constructor? How can I still declare the variable in the class definition but initialize it in the constructor?
Thanks for any answers!
Use the ctor-initializer. Members are initialized after base classes and before the constructor body runs.
MyClass::MyClass() : myObject(1,2,3) {
...
}
You can use an initializer list.
class MyClass {
public:
MyClass() : myObject(1,2,3){ }
AnotherClass myObject;
};
Google for Constructor initialization lists
http://www.learncpp.com/cpp-tutorial/101-constructor-initialization-lists/
class A
{
public:
A(int);
};
class B
{
public:
B();
private:
A my_a_;
};
// initialize my_a by passing zero to its constructor
B::B() : my_a_(0)
{
}
always use the initializer list:
MyClass::MyClass() :
myObject( 1, 2, 3 )
{
//myObject = don't do this, bad practice!
}
see http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6
The best method I can think of is to initialize the member in the class ctor, like so:
class MyClass
{
public:
MyClass(int param)
: m_Object(param)
{ };
private:
OtherClass m_Object;
};
You can then explicitly initialize the member with whichever ctor you want (as well as providing multiple ctors with different params for both classes).
Or provide proper constructors:
struct Foo{
Foo(const Bar& b): myBar(b){}
Bar myBar;
}
//...
Foo myFoo1( Bar(1,2,3) );
Foo myFoo2( Bar(3,2,1) );
Or if you don't want to expose bar then you can set parameters, for example
struct Square{
Square(const int height, const int width): myDimension(width,height){}
Dimension myDimension;
}
//...
Square sq(1,2);
Square sq(4,3);