I have an abstract base template class that contains members functions, some that are void, others returning data types ranging from primitive data types to the template parameter data type. I am still new to C++, and I know that I don't necessarily have to implement the pure virtual functions in the base class unless I wish to call them in the derived classes. This idea was fine for member functions that had no return value. For a function that returned an integer, I returned a 0. But when I got to a function that returned a reference to T, the template parameter, I did not know what to do. I tried the two following returns.
template <typename T>
T& AbstractBaseClass<T>::function(){
return T();
}
and
template <typename T>
T& AbstractBaseClass<T>::function(){
return T& tmp= T();
}
But neither seem to work, and I cannot not define these functions because I get an undefined reference error for the functions. I assume this error is because the functions are templates. What is the appropriate way to implement a non-void pure virtual function?
template <typename T>
class AbstractBaseClass{
public:
virtual ~AbstractBaseClass() = 0;
T& function();
}
template <typename T>
T& AbstractBaseClass<T>::function(){
//what must I do here when I don't have any member variable
}
Here is an example of a pure virtual function and a derived class that implements it (some member functions omitted for clarity):
template <class T>
class Base
{
public:
virtual T& get() = 0;
virtual ~Base() = 0;
};
template <class T>
Base<T>::~Base() {}
template <class T>
class Derived: public Base<T>
{
T t;
public:
T& get() override { return t; }
};
Note how get() in Base has no implementation, and the implementation of get in Derived uses a new data member not available in Base.
Note also that a pure virtual destructor, unlike other pure virtual functions, must have an implementation. Normally one doesn't need a pure virtual destructor if there are other pure functions in the class though. It is shown here for illustration.
Related
I have created some code that uses a function template and an overload (not a specialization) of that function. When I call the function with an object of a class that is derived from the parameter in the it uses the template resulting in a compile error. I have been reading http://www.gotw.ca/publications/mill17.htm
and I had the impression that overloaded functions would always have preference above templates. I have created a similar do-nothing example:
class ITest
{
public:
virtual void foo()=0;
};
class TheTest:public ITest
{
public:
virtual void foo()
{
}
};
class test
{
public:
template<typename T>
void handle(T par)
{
par++;
}
void handle(ITest &t)
{
t.foo();
}
};
void TestThem()
{
test t;
t.handle(2);
t.handle(3.0);
TheTest t2;
t.handle(t2);
}
I would expect t.handle(t2) to call the overloaded void handle(ITest &t) since TheTest is derived from ITest. However the compiler selects the template which generates an error.
When I change void handle(ITest &t) to void handle(TheTest &t) it compiles fine.
I fixed it by removing the template function and overloading for all used types, but this is cumbersome since they all do exactly the same thing.
I had the impression that overloaded functions would always have preference above templates.
This is true, but only when the non template function and template function are equally good. In that case the non template function is used.
In this case though they are not both equally good. t2 is a TheTest, when overload resolution runs it finds void handle(ITest &t) and void handle(TheTest par) (I've instantiated the template here). Sine the template version will give an exact match it is a better function and is chosen.
The way to fix this is to constrain the template to only work for types that aren't derived from ITest. If you change the template function to
template<typename T, std::enable_if_t<!std::is_base_of_v<ITest, T>, bool> = true>
void handle(T par)
{
par++;
}
Then it will only be called for types that don't derive from ITest. You can see it working in this live example.
I have the following class hierarchy:
template<typename T>
class GridMetric{
virtual GridMetric* getNeighbors(T value) = 0;
};
template<size_t N, typename T, typename Derived>
class MatrixBase : public GridMetric<T>{
virtual MatrixBase<N,T,Derived>* getNeighbors(T value){return nullptr;}
};
template<size_t N, typename T>
class MatrixND : public MatrixBase<N,T,MatrixND<N,T>>{
virtual MatrixND<2,T>* getNeighbors(T value){ /* ... */}
};
template<typename T>
class MatrixND<2,T> : public MatrixBase<2,T,MatrixND<2,T>>{
virtual MatrixND<2,T>* getNeighbors(T value){ /* ... */}
};
template<typename T>
class Vector : public GridMetric<T>{
virtual MatrixND<2,T>* getNeighbors(T value){ /* ... */}
};
So my abstract class GridMetric has two derived classes, Vector and MatrixBase. My Matrix Base class has crtp style derived class MatrixND and there is a specialization of MatrixND with N=2.
Each class shall have a virtual function getNeighbors to return a MatrixND<2,T> pointer.
It all works fine, except the MatrixND class complains that MatrixND<2,T> is an invalid covariant return type:
error: invalid covariant return type for ‘MatrixND<2ul, T>* MatrixND<N, T>::getNeighbors(T&) [with long unsigned int N = 3ul; T = double]’
virtual MatrixND<2,T>* getNeighbors(T& in){
My first question is why and how can I deal with that? Since MatrixND<2,T> inherits from MatrixBase!
My second question: Is it bad design, because I would always return raw pointers? I read the expression return new obj.. a lot, but also that this is apparently bad design. Are there other possibilities to achieve the same?
Edit: So, after some time, I realized, that the original plan wasn't going to work out and I found a much easier solution by templating the class, where I want to use those classes.
Anyway, the question stands, why the specialized MatrixND class can not be a covarient return type in the general MatrixND class. I didn't find anything saying it isn't allowed.
MatrixND<2,T>, basic case, no need for an explanation.
Vector<T> inherits from GridMetric<T>, so anything deriving from GridMetric<T> (including MatrixND<2,T> here) is fine.
But, the general form MatrixND<N,T> (N != 2) inherits from MatrixBase<N,T,MatrixND<N,T>> which redefines the virtual function as:
virtual MatrixBase<N,T,Derived>* getNeighbors(T value){return nullptr;}
which forces the return type of MatrixND<N,T> to now derive (at least) from MatrixBase<N,T,MatrixND<N,T>>.
Not from GridMetric<T> (as for Vector<T>) or MatrixBase<2,T,MatrixND<2,T>> (as for the specialization MatrixND<2,T>), but: MatrixBase<N,T,MatrixND<N,T>>, with (N != 2).
And why this is not a covariant return type? Because MatrixND<2,T> does not inherit from MatrixBase<N,T,MatrixND<N,T>> when N != 2.
Either remove the function redefinition within MatrixBase<N,T,MatrixND<N,T>> or change its return type to GridMetric<T>, and this will work (as MatrixND<2,T> inherits from GridMetric<T>).
What would be the syntax to inherit constructors (some of them are template) from a class template in C++11 ?
template <class T>
struct Base
{
using type = T;
explicit constexpr Base(const type& x): value{x} {};
template <class U> explicit constexpr Base(U&& x): value{std::forward<U>(x)} {};
type value;
}
struct Derived: Base<bool>
{
using Base::Base<bool>; // Does not seem to work ?!?
}
You derive from Base<bool>. So your base class is Base<bool>, and inheriting the constructors is done via
using Base<bool>::Base;
Live on Coliru
You do not need Base<bool> after the ::, in fact the code doesn't compile if you put it. The constructors are still referred to as Base, and not Base<bool>. This is consistent with referring to member functions of class templates: you use e.g. void Foo<int>::f() and not void Foo<int>::f<int>() to refer to the Foo's member function f().
I'm wanting to invoke a specialized templated function by using a pointer to it's base type. I'm not sure if this possible so I'm open to suggestions and/or alternatives. Here is an example of my situation:
class CBase {};
class CDerivedClass : public CBase {};
template<class T>
int func<T>(T &x) { ... };
template<>
int func<CDerivedClass>(CDerivedClass &x) { ... };
I have another function that manages a list of CBase pointers and then calls the func() function.
void doStuff()
{
CBase *foo[10] = { ...... };
for (int i = 0; i < 10; ++i)
func(*foo[i]);
}
Is there a way to get the derived type, so that func(CDerivedClass &) is called?
What about Template Subclassing? This idiom allows you to use compile-time polymorphism in C++. The cost of it is higher verbosity (such as specifying the whole class hierarchy up to the current class). In your case:
template <typename TSpec> class Klass {};
template <typename TSpec> struct SpecTag {};
template <typename TSpec> class Klass<SpecTag<TSpec> > {};
template <typename TSpec>
int func(Klass<TSpec> &x) { ... };
template <typename TSpec>
int func(Klass<SpecTag<TSpec> > &x) { ... };
The "Visitor" pattern comes to the rescue in this case. It enables polymorphic behavior in an algorithm implemented outside the class. Some support code is required inside the class, but new algorithms can later be added, existing algorithms modified, etc., without affecting the class.
Alternative solution : from your example, it's obvious that you just should to use a virtual method in CBase, so you just have to define a virtual function in CBase and an overriding function in the derived class.
I have a template container class that I derive from called MyContainer. MyContainer defines methods like Get(), Set(), etc. to access individual elements. I'd like to make a bitfield class implemented as a MyContainer<char>, where each char element holds CHAR_BIT number of bits. However, to allow the user to operate on individual bits rather than entire bytes, I would have to make Get() and Set() virtual, which is illegal. What are some alternatives?
I was thinking of defining GetBit() and SetBit() in the derived class, but this would violate the Liskov substitution principle. (Think of a SortMyContainer() function.)
EDIT: Here is a simplified example:
template <typename Datatype>
struct MyContainer
{
virtual Datatype Get();
};
template <typename Datatype> // Error: Templates may not be virtual.
virtual Datatype MyContainer<Datatype>::Get() // EDIT: The problem was on this line. The "virtual" keyword should only appear with the function declaration.
{
// ...
}
It is not illegal, only template virtual member functions are.
// valid
template<typename T> class MyContainer {
virtual void set(const T &) = 0;
}
// not valid
class MyContainer {
template <typename T> virtual void set (const T &) = 0;
}
If I got you wrong, please consider placing a code-sample.
edit after your adding of example code:
template <typename Datatype>
virtual // <-- nope, not here
Datatype MyContainer<Datatype>::Get()
{
// ...
}
virtual is only part of the declaration inside the class body. This should be valid:
template <typename Datatype>
Datatype MyContainer<Datatype>::Get()
{
// ...
}
However, note that the definition must be visible at the point of template instantiation. So either put it in the header-file, too (or in an extra-header that you then include into your real header), or leave it in the class-body.
(please nobody mention exported templates now, you and I know them a lot, but they are not quite a beginner topic, and deprecated with the next standard)
You appear to be confused about what constitutes a template. Class templates may have virtual functions, and indeed, those template parameters may appear in those function's signatures.
template<typename T> class an_interface {
virtual T Get() = 0;
};
class a_class : public an_interface<int> {
};
This is perfectly valid. What's not perfectly valid is
class an_interface {
template<typename T> virtual T Get() = 0;
}
Unless the specific member function in question has it's own, separate template parameters, the member function is not a template and may be virtual, irrespective of if it was generated from a class template.