Say I have a fixed class Base
that I cannot modify (e.g. in a static lib), which uses an internal data type in its constructor. I would like to provide a version of the Base
class that uses a more generic data type instead but otherwise behaves the same way. So I want to write a Derived
class that takes a different data type in its constructor and does the conversion before calling Base
's constructor.
I see two ways of doing that and I would like to know if there is any preference to one or the other. Or if there is a third one that I missed.
Option 1 uses an initialization list. Since I need to call some conversion code before calling the
Base
's constructor, I wrote a static function that I can call from the initialization list.Option 2 uses
placement new
to callBase
's constructor at the end ofDerived
's constructor after I do the conversion directly.
Here's the code. I am using personal_int
as a stand-in for the internal data structure that I want to encapsulate away. Derived
uses int
as a stand-in for the more generic data structure. The conversion occurs during Derived
's constructor call.
#include <iostream>
using namespace std;
class Base
{
public:
typedef int personal_int;
Base() : m_i(0) {}
Base(int i) : m_i(i) {}
personal_int get_i()
{
return m_i;
}
protected:
personal_int m_i;
};
class Derived1 : public Base
{
public:
static const Base::personal_int multiply_n(int i, int n)
{
return static_cast<Base::personal_int>(i*n);
}
Derived1(int i) : Base(multiply_n(i, 2)) {}
int get_i()
{
return static_cast<int>(m_i);
}
};
class Derived2 : public Base
{
public:
Derived2(int i)
{
Base::personal_int pi = static_cast<int>(i*2);
new (this) Base(pi);
}
int get_i()
{
return static_cast<int>(m_i);
}
};
int main()
{
Derived1 d1(3);
Derived2 d2(3);
cout << d1.get_i() << endl;
cout << d2.get_i() << endl;
return 0;
}
These are the arguments I could find in favor of one option or the other:
Pro Derived1
:
- It avoids
placement new
(possible problems with deallocation in more complex cases?) Base
does not need an empty constructor. This could be a severe limitation forDerived2
if the empty constructor was missing inBase
since I cannot modify the class in the first place- It might be less efficient to first initialize the data structure for the empty constructor call and then initialize it again during the
placement new
call.
Pro Derived2
:
- No need to split the conversion into a different function when all the derived class does is abstract the constructor of the base class
I think Derived1
is the superior (even more efficient?) one. So would there be any reason to go for Derived2
? Or is there a third option that would be preferable?
Edit: Apparently, my question has caused some confusion because it is very simplified.
The reason I am using a special function multiply_n
instead of putting the conversion directly in the initializer list is that in a more realistic scenario, I am not not simply converting from int
to personal_int
(which is essentially the same).
Instead, I could be converting between more complex data structures, e.g. from an xml string in Derived
to a struct in Base
. A conversion like this would span multiple lines of code and could not simply be placed in the initializer list.