How to define member function coming from non-template base class - c++

I have a non-templated abstract base class. How do I define the pure virtual function outside derived class?
#include <iostream>
class base {
public:
virtual void func() = 0;
};
template<typename T>
class der : public base{
};
template<typename T>
void der<T>::func()
{
std::cout<<"In Der";
}
The following error comes up:
template.cpp:13: error: no ‘void der<T>::func()’ member function declared in class ‘der<T>’
template.cpp:13: error: template definition of non-template ‘void der<T>::func()’

Declare the member function.
template<typename T>
class der : public base{
public:
void func();
};
There's no automatic declaration of member functions that you may or may not wish to override in a derived class - you have to explicitly declare and define these. Whether the derived class is implemented as a template or not doesn't matter for this.

You must declare the virtual override in the derived class definition.
template <typename T>
class der : public base {
public:
virtual void func();
};

This will work:
#include <iostream>
class base {
public:
virtual void func() = 0;
};
template<typename T>
class der : public base{
public:
void func()
{
std::cout<<"In Der";
}
};
It has been recommended to me to drop function definitions straight into templates when possible, except for specializations.
edit: 'inline' was not the best choice of word here

Related

C++: inherited classes have pure virtual functions with identical names. How can I override them separately in my base class?

The following code illustrates my question:
namespace foo1
{
class bar1
{
public:
virtual void fn() = 0; //this must remain pure virtual
};
};
namespace foo2
{
class bar2
{
public:
virtual void fn() = 0; //this must remain pure virtual
};
};
class bar3: public foo1::bar1, public foo2::bar2
{
public:
//can i separately override virtual functions from inherited
//classes that have the same name?
void foo1::bar1::fn() override {std::cout << "bar1";} //error
void foo2::bar2::fn() override {std::cout << "bar2";} //error
};
int main()
{
bar3* obj = new bar3();
((foo1::bar1*)obj)->fn(); //i want this to print "bar1"
((foo2::bar2*)obj)->fn(); //and this to print "bar2"
}
Basically I want to be able to override inherited functions, such that by simply casting my base class object to one of the inherited classes, I can call the different functions even though they have the same name. Is this possible?
Sure.
struct foo1bar1helper:public foo1::bar1{
void fn()final{foo1bar1fn();}
virtual void foo1bar1fn()=0;
};
now bar3 just inherits from this instead of bar1 and overrides foo1bar1fn(),
Do the same with bar2.
You can also use CRTP to dispatch and do away with the extra vtable lookup;
template<class D>
struct foo1bar1helper:public foo1::bar1{
void fn()final{static_cast<D*>(this)->foo1bar1fn();}
};
template<class D>
struct foo2bar2helper:public foo2::bar2{
void fn()final{static_cast<D*>(this)->foo2bar2fn();}
};
class bar3:
public foo1bar1helper<bar3>,
public foo2bar2helper<bar3>
{
public:
void foo1bar1fn(){}
void foo2bar2fn(){}
};
You can not do that. When you do foo1::bar1::fn(), compiler thinks that you are defining function fn of 'bar1' of 'foo1' namespace in class bar3. Hence compiler is throwing below error.
error: cannot define member function ‘foo1::bar1::fn’ within ‘bar3’
But when you extend from an abstract class, you need to give the definition of the function (which should be part of your derived class) in derived class.

Initialization of static template member in CRTP

I try to initialize a static member of a CRTP base class. The base class holds a static template member of the derived class, while the derived class defines other data members. I want to statically initialize this variable. In code, a minimal example would be the following:
template<typename DERIVED>
class base {
public:
static DERIVED x;
};
class derived : public base<derived>
{
public:
int a;
};
int base<derived>::x {0};
int main()
{}
However, the above does not compile, but gives the error message error: specializing member 'base<derived>::x' requires 'template<>' syntax.
How can I get the static initialization to work?
The correct syntax is:
template <class T>
class base {
public:
static T x;
};
template <class T>
T base<T>::x{};
Note that you can't initialize x to a specific integer value, since then your base class won't compile when DERIVED is e.g. an std::string.
You probably also want your inheritance to be explicitly public or private. I.e.:
class derived : public base<derived> {
public:
int a;
};
Edit: To specialize x and it's initialization for specific types T, you have to specialize base itself. I.e.:
class A;
template <>
class base<A> {
public:
static int x;
};
// Note missing "template <>" here.
int base<A>::x{ 5 };
class A : public base<A> { };
This seems rather cumbersome, since you need to already forward declare A in this case before declaring the specialization. To me it feels you might want to rethink your design. Is this really required or is there a simpler way to accomplish what you want?
I have found the static initializer trick, which works in the above setting, too. It was described here and here. In the above context, it would be as follows:
#include <iostream>
template<typename DERIVED>
class base {
public:
static inline DERIVED x;
};
class derived : public base<derived>
{
public:
int a;
struct static_initializer {
static_initializer()
{
derived::x.a = 1;
}
};
static inline static_initializer static_initializer_;
};
int main()
{
std::cout << derived::x.a << "\n";
}
The above output the value 1.
Note: this works with C++17.

Template specialization of pure virtual method

Expected this code to compile and work
template<class T>
class Base
{
virtual void method() = 0;
};
template<>
void Base<int>::method() { std::cout << "overrided" << std::endl; }
Base<int> base;
But it gives the 'Base<int>': cannot instantiate abstract class error. Thought partial specialization would make Base<int> non-abstract and allow to instantiate it.
Is there a working solution as short as this one and that keeps the Base class abstract? Otherwise I can make the Base class non-abstract or use Nicol Bolas's solution from here: Template specialization and inheritance
If it won't work for a non-template class, why should it work for a template class?
#include<iostream>
class Base
{
virtual void method() = 0;
};
void Base::method() { std::cout << "overrided" << std::endl; }
Base base;
errors:
10 : error: cannot declare variable 'base' to be of abstract type 'Base'
Base base;
^
3 : note: because the following virtual functions are pure within 'Base':
class Base
^
8 : note: virtual void Base::method()
void Base::method() { std::cout << "overrided" << std::endl; }
^
Compilation failed
What about specialization of whole class (instead of just one member function):
template<class T>
struct TempClass
{
virtual void f() = 0;
};
template <>
struct TempClass<int>
{
virtual void f()
{
//...
}
};
Note that TempClass<int> is no longer abstract class, but other Base classes are still abstract classes, (TempClass<float>, TempClass<double>, TempClass<SomeClassType>, ...).
and
it won't contain fields that generic class TempClass contains. You will have to copy-paste them from generic Base or, which is more clever solution,
you'll create base class with fields that both specialization have and then make those template classes inherit from that base class:
template <typename T>
struct Base
{
// some members that all Base classes have
};
template <typename T>
struct TempClass: Base<T>
{
virtual void f() = 0;
};
template <>
struct TempClass<int>: Base<int>
{
virtual void f()
{
//...
}
};
This way ugly copy-paste wasn't needed.
It is possible to provide an implementation of a pure virtual function in a class. That does not make the class instantiable.
class Base
{
virtual void method() = 0;
};
void Base::method() { /* Do something */ }
// This is still a problem since Base
// is still an abstract class, i.e. it is not still not
// instantiable.
Base base;

How to change the return type of an inherited class member

I've just recently learned about templates and I was a bit curious. Is it possible to change the return type of an inherited function to the template type?
For example:
class A{
public:
int getSomething();
};
template<typename T>
class B : public A{
public:
T getSomething();
};
You can do that, but the function in B will hide the function in A. When you use someB.getSomething(), only the function in B will be seen. This is true regardless of whether the return type matches or not.
You can bring A::getSomething into scope if you wish:
template<typename T>
class B : public A {
public:
using A::getSomething;
T getSomething();
};
However, this using declaration is more useful when A::getSomething has a different signature, unlike here, where they both have the same parameter list.
To override getSomething here, it must be marked as virtual:
class A {
public:
virtual int getSomething();
};
Now, trying to instantiate B with something other than int fails to compile.
There is still one case where you can change the return type and still override the function. This is a covariant return type, where the derived class returns something more derived than what the base class returns:
class A{
public:
virtual A* getSomething();
};
class B : public A{
public:
B* getSomething() override;
};

Is it safe if a template contains virtual function?

Early binding for template and late binding for virtual function. Therefore, is it safe if a template contains virtual function?
template<typename T>
class base {
public:
T data;
virtual void fn(T t){}
};
It is completely safe. Once you instantiate the class template, it becomes normal class just like other classes.
template<typename T>
class base {
public:
T data;
virtual void fn(T t){}
};
class derived : base<int> {
public:
virtual void fn(int t){} //override
};
base<int> *pBase = new derived();
pBase->fn(10); //calls derived::fn()
I would also like to point out that while it is allowed virtual function in a class template, it is not allowed virtual function template inside a class (as shown below):
class A
{
template<typename T>
virtual void f(); //error: virtual function template is not allowed
};
Yes, it's quite safe. You'd use it by having a class derive from it:
class derived : public base<int> {
virtual void fn(int) { std::cout << "derived"; }
};
Of course, if it contains any other virtual functions (i.e., is intended to be used as a base class) you generally want to make the dtor virtual as well.
There is no safety concern associated with virtual function inside a template class. It is as good as, having a virtual function inside a normal class.