Can't friend a class that virtual inherits from it in C++ - c++

I want to make it so that only one class, Der, can subclass a Base class. So I made the constructor of Base private, and added Der as a friend of Base:
struct Base {
template<class T>
friend struct Der;
private:
Base() = default;
};
template<class T>
struct Der : Base {};
This works great.
However another struct, DerDer, inherits from Der, multiple times with different template arguments.
struct DerDer : Der<int>, Der<char> {};
This is a problem because now there are two Base in the hierarchy, so the solution is to make Der virtually inherit from Base:
template<class T>
struct Der : virtual Base {};
This now breaks, I believe if a class is virtually inherited then the most derived class is responsible for calling the constructor (not really sure why). Which is a problem because DerDer is not a friend of Base and so therefore can not access it's constructor.
How can I fix this?
(It seems like it's an implementation detail that virtual inheritance makes the most derived class call the constructor, and so friending should respect that it's otherwise correct to do this and this is a kind of a bug in the compiler (or standard))

One option is to use a private nested struct to control permission to construct a Base.
struct Base {
template<class T>
friend struct Der;
private:
struct Permission {};
public:
Base(Permission) {}
virtual ~Base() = default;
};
template <class T>
struct Der : public virtual Base {
protected:
using Permission = Base::Permission;
public:
Der() : Base(Permission{}) {}
};
struct DerDer : Der<int>, Der<char> {
DerDer() : Base(Der<int>::Permission{}) {}
};
Now writing constructors is a little awkward, but the only way to construct a Base is to be or inherit Der<T> for some T.

How can I fix this?
The simplest solution is to make Base::Base() a public member function.

Related

Is there a way to forbid a base class method call in the derived class?

In c++ "protected" modifier allow method calls only in derived classes. Is it possible to implement inverse logic - prohibit calling a base class method in the derived classes? The code below illustrates what I want to get.
class Base
{
int data;
protected:
// This constructor should be called only in the derived classes
Base(int d): data(d) { }
public:
// This construcor can be called wherever except a derived classes!
Base(): data(0) { }
};
class Derived : public Base
{
public:
// The developer must not forget to initialize "data"
Derived() : Base(10) {}
// I want to get a compilation error there
Derived() : Base() {}
};
Is it possible to [...] prohibit calling a base class method in the derived classes?
Yes. By using private access specifier. Private names are accessible only to the class itself.
It is not inverse logic however. It is not possible for reduce accessibility of of otherwise public name from derived classes.
// This construcor can be called wherever except a derived classes!
There is no way to do this. A public function can be called by anyone and there is no SFINAE trick you can use to stop it if it is called by a derived class since the constructor has no idea where it is called from.
This seems like a XY problem. Although I do not recommend this (I recommend rethinking the design) I found (for better or worse) a solution inspired from the CRTP pattern:
template <class D = void>
class Base
{
protected:
int data;
protected:
// This constructor should be called only in the derived classes
template <class Der = D, class = std::enable_if_t<std::is_base_of_v<Base, Der>>>
Base(int d): data(d) {}
public:
// This constructor can be called wherever except a derived classes!
template <class Der = D, class = std::enable_if_t<!std::is_base_of_v<Base, Der>>>
Base(): data(0) { }
};
class Derived : public Base<Derived>
{
int mydata = 1;
public:
// The developer must not forget to initialize "data"
Derived() : Base(24) {}
// I want to get a compilation error there
//Derived() : Base() {} // (1) compilation error here
};
auto test()
{
Base b1{};
//Base b2{24}; // (2) compilation error here
Derived d{};
}
Of course there are problems with this. For starters there is nothing stopping from creating a derived class as class Derived : public Base<void>.
And if you want, you can add a common base class
class Base_l0
{
};
template <class D = void>
class Base_l1 : Base_l0
{
};
class Derived : public Base_l1<Derived>
{
};
The short answer is no.
In C++, there is only public protected and private. There is no middle ground. Your functions are either accessible from everywhere (public), from nowhere except the class itself (private), or from the class and its children (protected).
I only want to force the user to perform some additional actions wlile inheritting [sic]. For example, to avoid random errors.
If calling the default constructor causes errors by calling it while inheriting from it, then then it is probable it causes errors when you are not inheriting from it. That means you probably shouldn't have this constructor as public anyway, if at all.

Weird inheritance pattern

Suppose I have a base class like this:
class Abstract {
public:
/* This type should be the deriver of this class */
virtual DerivedType foo(void) = 0;
};
And I want DerivedType to be different depending on who derives from this class. In fact I want DerivedType to be the type that Derives from Abstract.
I realize that I could do something like this:
template<typename der_t>
class Abstract {
public:
virtual der_t foo(void) = 0;
};
And then it should be used like this:
class Derived : public virtual Abstract<Derived> { };
Unfortunately there is no way to force someone to pass in the right type in the template. That is someone could do this:
class Derived : public virtual Abstract<int> { };
So is there any better way to do this, or is there a way to force someone to pass in the right parameter?
The usual trick for CRTP's is to have a private constructor that only the passed-in class can access via a friend directive:
template <class Derived>
struct Crtp {
private:
friend Derived;
Crtp() = default;
};
It isn't perfect, but guards against errors.
Note : static_asserting is not a practical solution, because at the time Crtp is instantiated Derived is still incomplete, and can't be checked for base classes.

Check if constructors of subclass are public in 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

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>.

How to force use of curiously recurring template pattern in C++

I have the following base template class.
template<typename T>
class Base {
public:
void do_something() {
}
};
It is intended to be used as a curiously recurring template pattern. It should be inherited like class B : public Base<B>. It must not be inherited like class B : public Base<SomeoneElse>. I want to statically enforce this requirement. If someone uses this wrong, I expect an error in the compiling phase.
What I'm doing is putting a static_cast<T const&>(*this) in do_something(). This way the class inheriting the template is or inherits from the class provided as the template parameter. Sorry for the confusing expression. In plain English, it requires B is or inherits from SomeoneElse in class B : public Base<SomeoneElse>.
I don't know if it's the optimal way to achieve this. Looks gross to me.
However I want to do more. I want to ensure B is SomeoneElse itself. How can I do that?
Make the constructor (or destructor) of Base private, and then make T a friend. This way the only thing that can construct/destruct a Base<T> is a T.
If your class contains some code that says:
T* pT = 0;
Base *pB = pT;
Then there will be a compiler error if T is not assignment-compatible with Base.
This kind of check is formalised in C++11 so you don't have to write it by hand and can get helpful error messages:
#include <type_traits>
template<typename T>
class Base {
public:
void do_something()
{
static_assert(
std::is_base_of<Base, T>::value,
"T must be derived from Base");
}
};
class B : public Base<B> { };
int main()
{
B b;
b.do_something();
}
As to ensuring that Base's type parameter is exactly the class that is deriving from it, that seems conceptually flawed. A class that is acting as a base class can't "talk about" the type that is inheriting it. It may be inherited more than once via multiple inheritance, or not at all.
Two good answers so far. Here is another which uses the idiom of generating custom access keys to certain methods (in this case a constructor). It provides an absolute guarantee of correct use while not exposing private methods in the base to the derived.
It can also be used to control access to other methods in the base class on a case-by-case basis.
template<class Derived>
struct Base
{
private:
// make constructor private
Base() = default;
protected:
// This key is protected - so visible only to derived classes
class creation_key{
// declare as friend to the derived class
friend Derived;
// make constructor private - only the Derived may create a key
creation_key() = default;
};
// allow derived class to construct me with a key
Base(creation_key)
{}
// other methods available to the derived class go here
private:
// the rest of this class is private, even to the derived class
// (good encapsulation)
};
struct D1 : Base<D1>
{
// provide the key
D1()
: Base<D1>(creation_key())
{}
};