Check if constructors of subclass are public in C++ - c++

Hope this is not duplicated, but wasn't able to find an elegant solution. Is it possible to say that subclasses of a special base class can only created in a template factory function? Because of simplicity I only want to force this behavior in the base class. Here is an simple example:
template <class T>
T* createBase();
template<typename T>
class Base {
protected:
template <class T>
friend T* createBase();
static T* create()
{
return new T();
}
};
class TestClass1 : public Base<TestClass1>
{
public:
TestClass1() : Base() {}
};
template <class T>
T* createBase()
{
static_assert(std::is_base_of<Base<T>, T>::value, "use the createBase function only for Base<T> subclasses");
return Base<T>::create();
}
Actually this is allowed:
TestClass2 *testClass = createBase<TestClass2>();
TestClass2 tester;
But I only want to have this:
TestClass1 *testClass = createBase<TestClass1>(); //allowed
TestClass1 tester; // compile error
For sure I know I only have to put the constructor of TestClass1 private or protected. But it would be really nice to say that in the Base object.
Edit:
An compile error when the constructor of the subclass is public would be a also a nice solution. Maybe with a static_assert().

You can't control the accessibility of a constructor from the base class, even with CRTP.
What you can do is add a static_assert in the base ctor checking that the T a.k.a the derived class has no publicly accessible default ctor:
template <class T>
class Base {
public:
Base() {
static_assert(!std::is_default_constructible<T>::value,
"T must not be default constructible");
}
};
the static_asswert doesn't work on class scope for reasons showned here: CRTP std::is_default_constructible not working as expected

Related

How to call the base class method in C++?

I am working on a C++ program. For one of the use case, I have a class which is derived from its template class. So, I'm wondering how we can call the base class method inside the derived class method?
Example:
template <typename base>
struct derived : public base
{
void aFunction()
{
// need to call a base function() here
}
};
One of the way could be something like base::aBaseFunction(), but I am not sure?
I am new to OOP programming, so looking forward to learning a new concept through this problem statement.
If you want to explicitly use the base's member, make the type explicit like you found:
template <typename base>
struct derived : public base
{
void aFunction()
{
base::function();
}
};
If you would rather have the usual unqualified-lookup behaviour, make this explicit instead:
template <typename base>
struct derived : public base
{
void aFunction()
{
this->function();
}
};
Both of these behave exactly like they do in non-templates.

Why can I omit the template parameter specification in some cases?

I have a question as I cannot explain why something works where I probably have made a mistake. Maybe somebody kind can help me to improve my C++ culture by explaining to me why this is so.
For better transparency I simplifiy the code quite a bit.
I have a template virtual class that is like this:
template<class Node>
class tXmlNode
{
public:
tXmlNode();
virtual ~tXmlNode();
protected:
Node* node;
}
;
From this I derive several classes.
Mostly I derive from it another template class such as this one:
template<class Part>
class tXmlMove : public tXmlNode<Part>
{
public:
tXmlMove(Part* part);
~tXmlMove();
protected:
int n_translate;
};
with this implementation (reduced to the constructor):
template<class Part>
inline tXmlMove<Part>::tXmlMove(Part* part) : tXmlNode<Part>(part)
{
//do some construction
}
;
As you can see I delegate some part of the construction to the parent class constructor. Works fine.
Now I have another derived class but which is derived from a specialized parent class (the specialisation is a self-specialisation but from other classes with similar specialized parent it works exactly as for this one):
class tXmlCaseDefinition : public tXmlNode<tXmlCaseDefinition>
{
public:
tXmlCaseDefinition();
tXmlCaseDefinition(const pugi::xml_node& parent);
~tXmlCaseDefinition();
protected:
int n_shapes;
}
;
(I guess it is due to the specialization that I do not need to construct this class as a template class.)
Its not-default constructor is implemented as follows:
nXml::tXmlPart::tXmlPart(
const pugi::xml_node& parent,
const int npos) : tXmlNode(parent, npos), this_id(""), this_type(""), description("")
{
}
;
As you can see I did not delegate to the parent constructor by using tXmlNode<tXmlCaseDefinition>(parent,npos) but simply tXmlNode(parent,npos). I didn't pay attention to that and it works for some mysterious reason. I simply cannot understand why. Can somebody explain?
Also do I need to use tXmlNode<Part>(part) or can I use tXmlNode(part) instead for classes not derived from the specialized parent class or is this only possible when I have a spezialized parent?
Thank you very much!
Within the definition of a template class (more formally, the "current instantiation"), there is something called an injected-class-name, which is simply the name of the template sans arguments. For example:
template<class T>
struct Foo
{
Foo* ptr; // refers to Foo<T>
};
When you derive from a templated class, the base class' injected-class-name is inherited. Therefore you can also refer to the base class sans template arguments (assuming the name is accessible; some ancestor didn't privately inherit from it):
template<class T>
struct Base
{
};
struct Derived : Base<int>
{
Base* ptr; // refers to Base<int>
};
cppreference does a decent job of summarizing all the standardese here (Refer to [temp.local], [basic.lookup], and [basic.scope.class])

Access to protected constructor from static factory method in base class

I've got a static factory method in a base class.
Because of some reasons I want to each derived class will be instantiated by this factory method hence all these classes have protected ctors.
In real situation the Create function does more additional logic along with error handling.
class Base
{
public:
virtual ~Base() {}
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::unique_ptr<T>(new T);
// ...
}
protected:
Base() {}
};
class Derived : public Base
{
protected:
Derived() {}
};
int main()
{
std::unique_ptr<Derived> ptr;
Derived::Create(ptr);
}
That code obviously doesn't compile since we don't have access to the protected ctor.
prog.cc: In instantiation of 'static void Base::Create(std::unique_ptr<_Tp>&) [with T = Derived]':
prog.cc:33:24: required from here
prog.cc:17:35: error: 'Derived::Derived()' is protected within this context
17 | pOut = std::unique_ptr<T>(new T);
| ^~~~~
prog.cc:26:5: note: declared protected here
26 | Derived() {}
| ^~~~~~~
The first solution that seems to be the most common is friend declaration in derived class. However it works I don't like it because:
I have to add such declaration in each derived class
This is a friend
class Derived : public Base
{
protected:
Derived() {}
friend void Base::Create<Derived>(std::unique_ptr<Derived>&);
};
Thinking about more generic approach I was trying something like this:
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
static_assert(std::is_base_of_v<Base, T>, "T should be Base-family class.");
class CreateHelper : public T
{
public:
static void InternalCreate(std::unique_ptr<T>& pOut)
{
pOut = std::unique_ptr<CreateHelper>(new CreateHelper);
// ...
}
};
CreateHelper::InternalCreate(pOut);
}
It works but looks weird to me and:
The real pointer type is CreateHelper however outside this function we don't see that
This approach needs that Base-familiy should be polimorphic since we use pointer to base class (it's seems this condition should be always met but still it's worth to mention about that)
My questions are
What do you think about the last approach?
Is it considered as a bad design?
In general, a far better approach here is to simply refer to simple construction helper classes, then you can refer to make_unique() too:
class Base
{
protected:
struct Accessor
{
explicit Accessor() = default;
};
public:
Base(Accessor) {}
virtual ~Base() {}
template <typename T>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::make_unique<T>(Accessor());
// ...
}
};
class Derived : public Base
{
public:
Derived(Accessor) : Base(Accessor()) {}
};
Only drawback: Derived classes have to adapt their constructor(s) accordingly.
A general point: A factory should almost always be aware of its relevant types in general, at least of partial aspects of the relevant types, provided by polymorphism (interfaces) or/and via traits. So I think, this is a bit more convenient:
template <class T, typename std::enable_if<std::is_base_of<Base, T>::value>::type* = nullptr>
static void Create(std::unique_ptr<T>& pOut)
{
pOut = std::make_unique<T>(Accessor());
// ...
}
Further on: You might have to rethink about your general creation design here. The common approach here is to return the created object, not to fill a reference. With your current approach, you have to think about exception safety (contracts..) here at least twice for instance...
Possible approach:
template <class T, typename std::enable_if<std::is_base_of<Base, T>::value>::type* = nullptr>
static std::unique_ptr<T> Create()
{
auto pOut = std::make_unique<T>(Accessor());
// ...
return pOut;
}

C++ template declaration with inheritance list

Is it possible to declare a templated class in C++ along with the classes it inherits from? Basically I want to give the compiler a hint, that my templated class will always inherit another at declaration time.
Maybe some code will clear up why this is a problem for me:
template<typename T>
class GrandparentClass
{
public:
T grandparentMember;
};
//this needs to be only a declaration, since I do not want classes of ParentClass with random T
template<typename T>
class ParentClass : public GrandparentClass<T>
{
};
// this does not work:
//template<typename T>
//class ParentClass : public GrandparentClass<T>;
// this does not either, because then the child class cannot access the variable from the grandparent class
//template<typename T>
//class ParentClass;
template<>
class ParentClass<int> : public GrandparentClass<int>
{
public:
ParentClass()
{
grandparentMember = 5;
}
};
template <typename T>
class ChildClass : public ParentClass<T>
{
public:
void foo()
{
std::cout << grandparentMember << "\n";
}
};
Also, I cannot use C++ 11.
EDIT:
I found an easy way out of this:
template<typename T>
class ParentClass : public GrandparentClass<T>
{
public:
ParentClass() { ParentClass::CompilerError(); };
};
Just do not define CompilerError() method in the class and everything's fine.
A class declaration is only really useful for non-value variable declarations, like pointers and references. You can't access the class members or even instantiate it, though. Even if you knew that a declared class inherits from some other one, you still wouldn't necessarily be able to utilize that information in any way.
As such, it's only important for the compiler to know what the class inherits from once it learns its full definition.
After clarification in comments: if you want to prevent instantiation of a class template with some types, its definition is the place to do it. A simple static_assert inside the class body will do the trick; Boost.StaticAssert or older SFINAE tricks will do the job for pre-C++11 code.
If you are happy with delaying the error to link-time, rather than compile time, you can declare all the member functions of parent in parent.h, provide definitions in parent.cpp, and explicitly instantiate the finite list of classes that you want.
Parent.h
template<typename T>
class ParentClass : public GrandparentClass<T>
{
ParentClass();
};
class ParentClass<int>;
class ParentClass<long int>; // or whatever
Parent.cpp
template <typename T>
ParentClass::ParentClass() : grandparentMember(5) {}

Inheritance of templates - assignement failed

I run into a trouble with templates and inheritance. Consider following code:
#include <iostream>
using namespace std;
class TemplateBase {
public:
TemplateBase() {}
};
class TemplateA: public TemplateBase {
public:
TemplateA():TemplateBase() {}
};
template <class T>
class Base {
public:
Base() {}
};
class Derived: public Base<TemplateA> {
public:
Derived(): Base() {}
};
int main()
{
Base<TemplateBase>* a = new Base<TemplateBase>(); // ok
Base<TemplateA>* b = new Derived(); // ok
Base<TemplateBase>* c = new Derived(); // error: cannot convert ‘Derived*’ to ‘Base<TemplateBase>*’ in initialization
}
The problem is the assignment of pointer c, which fails from unknown reason for me. I am trying to assign the Derived<AnotherDerived> to Base<AnotherBase>, is this possible?
Thank you for any help.
Your Derived is a non-template class derived from Base<TemplateA>. In the line
Base<TemplateBase>* c = new Derived();
you are trying to refer to a Derived object via a pointer to Base<TemplateBase>. For the compiler, there is no relation between Base<TemplateBase> and Derived, hence it fails. The only possible base to use is Base<TemplateA> from which Derived is derived.
A possible solution is to templatize the Derived, like
template<typename T>
class Derived: public Base<T> {
public:
Derived(): Base<T>() {}
};
then use as
Base<TemplateBase>* c = new Derived<TemplateBase>;
See a live example here.
vsoftco gives a good outline of why this is invalid. An example of why this is the case in C++ is that although TemplateBase and TemplateA are related, Base<TemplateBase> and Base<TemplateA> are completely different. We could even specialize Base in a way which makes them have an incompatible interface:
template<>
struct Base<TemplateBase>
{
Base() = delete;
Base(int i) {}
}
Now it's obvious that Base<TemplateBase> and Base<TemplateA> can't be used in the same way, because one is default-constructable and one isn't. As such, it's impossible to use them polymorphically, because the compiler won't know what code to generate.
Polymorphism says a base class pointer can point to a derived class object.
But the same can't happen for templates.
Since Polymorphism is a dynamic feature and bound at run-time.
Templates are a static feature and bound at the compile time.
You make a common mistake, you think that relation between classes:
class A {};
class B : public A {};
Will propagate this relation to templates:
template <class T>
class Tmpl {};
Tmpl<A> a; Tmpl<B> b;
a = b; // fails!
So you expected that Tmpl<A> would be a parent to Tmpl<B> but that is not the case. To simulate that you would need to make a constructor, that allows such conversion:
template <class T>
class Tmpl {
T data;
public:
Tmpl() : data() {}
template<class Parent>
Tmpl( const Tmpl<Parent> &t ) : data( t.data ) {}
};
Tmpl<A> a; Tmpl<B> b;
a = b; // works!
For details you should look into smart pointer implementation, there is similar problem there - assignment from pointer to child from base needs to work.
The Derived class is derived from Base<TemplateA> so Base<TemplateBase>* c = new Derived() is equivalent to saying
Base<TemplateBase>* c = new Base<TemplateA>() which is incorrect because Base<TemplateA> is a different class altogether.
TemplateBase is a base class for TemplateA but same does not hold true for Base<TemplateBase> and Base<TemplateA>.