I am trying to reduce code duplication in an init function that initializes static members of derived classes. In my case, this function is called initTypeInfo
. Originally, each of my child classes ChildA
, ChildB
... ChildN
had their own initTypeInfo
. Once I decided to move initTypeInfo
into the Parent
class because pretty much all the code except the namespace of the static member (ChildA::s_typeInfo
vs. ChildB::s_typeInfo
...) was the same, I started to see problems with the static member s_typeInfo
. This variable is a smart pointer of type std::shared_ptr<TypeInfo>
Here is my code sample:
#include <string>
#include <memory>
#include <iostream>
struct TypeInfo
{
std::string name;
// other members ...
};
class Parent
{
public:
Parent(std::string name)
: m_name(name)
{
}
virtual std::shared_ptr<TypeInfo> getTypeInfo() = 0;
virtual void initTypeInfo()
{
// this function contains lots of common code, trying to avoid code duplication
std::shared_ptr<TypeInfo> typeInfo = getTypeInfo();
// initialize if it hasn't already been initialized
if (typeInfo == nullptr)
{
TypeInfo info {m_name};
// the variable Child<n>::s_typeInfo doesn't point to this allocated data :(
typeInfo = std::make_shared<TypeInfo>(info);
}
}
private:
std::string m_name;
};
class ChildA : public Parent
{
public:
ChildA(std::string name /*other params...*/)
: Parent(name)
{
initTypeInfo();
}
std::shared_ptr<TypeInfo> getTypeInfo()
{
return s_typeInfo;
}
private:
inline static std::shared_ptr<TypeInfo> s_typeInfo = nullptr;
// other members...
};
class ChildB : public Parent
{
public:
ChildB(std::string name /*other params...*/)
: Parent(name)
{
initTypeInfo();
}
std::shared_ptr<TypeInfo> getTypeInfo()
{
return s_typeInfo;
}
private:
inline static std::shared_ptr<TypeInfo> s_typeInfo = nullptr;
// other members...
};
int main()
{
ChildA ca1("childa1");
ChildA ca2("childa2");
ChildB cb1("Childb1");
return 1;
}
So my questions are:
- Is this bad design to begin with, where I initialize the static member in the parent class
- How can the code duplication here be addressed?
- I know returning by value is the preferred way to return smart pointers from a function. But in this case, how can I have my member
Child<n>::s_typeInfo
point to the data I allocated inParent::initTypeInfo()
The links I followed online pointed me to this link so I suppose I could achieve this with templates, but I'm not convinced that's the only way to do this.
Edit1:
In practice TypeInfo
doesn't only contain one data member. It's a complex class with several data members and methods. Initially I had initTypeInfo
functions in each derived class which would initialize each s_typeInfo
. However, turns out that the logic in all these initTypeInfo
functions were the same! The only difference was that the specific s_typeInfo
of each derived class had to be initialized. So I wanted a way to transfer the logic into the Parent
class (thereby reducing duplication) but also init the static s_typeNode
in the parent. I guess, alternatively the question could be, how do I get the child class shared_ptr
to point to the TypeInfo
I create in Parent::initTypeInfo()
?
The reason s_typeInfo
exists as a static member is because I want to share that class across all instances of a certain Child. So in my main if for example I start 4 instance of ChildA
I need them to share a single ChildA::s_typeInfo
and if I have 10 instances of ChildB
, I need them to share a single ChildB::s_typeInfo
.
Edit2:
Adding minimal example of code for what I want to achieve. I was expecting *(c.p)
to be 1 instead of nullptr
as I had returned from C::get()
by reference.
class C
{
public:
std::shared_ptr<int> & get()
{
return p;
}
inline static std::shared_ptr<int> p = nullptr;
};
int main()
{
C c;
std::shared_ptr<int> p1 = c.get();
if (p1 == nullptr)
{
p1 = std::make_shared<int>(1);
}
std::cout << *p1 << std::endl;
if (c.p == nullptr)
{
std::cout << "nullptr" << std::endl;
}
else
{
std::cout << *(c.p) << std::endl;
}
return 0;
}