I have a template base class Vect, from which VectDynamic is derived.
Base class (Vect.h):
template <typename Elem>
class Vect
{
public:
virtual Elem& operator[](std::ptrdiff_t);
};
Derived class (VectDynamic.h):
#include "Vect.h"
template <typename Elem>
class VectDynamic: public Vect<Elem>
{
std::size_t _dim;
Elem* _val;
public:
explicit VectDynamic(std::size_t dim = 0): _dim(dim), _val(new Elem[dim]) {}
VectDynamic(std::size_t, const Elem&);
VectDynamic(const VectDynamic&);
Elem& operator[](std::ptrdiff_t) override;
};
template <typename Elem>
VectDynamic<Elem>::VectDynamic(std::size_t size, const Elem& e):
_dim(size), _val(new Elem[size])
{
for (std::size_t i = 0; i < size; ++i) _val[i] = e;
}
template <typename Elem>
VectDynamic<Elem>::VectDynamic(const VectDynamic& v):
_dim(v._dim), _val(new Elem[v._dim])
{
for (std::size_t i = 0; i < v._dim; ++i) _val[i] = v._val[i];
}
template <typename Elem>
Elem& VectDynamic<Elem>::operator[] (std::ptrdiff_t i)
{
if (std::size_t(i) >= _dim)
throw std::out_of_range("VectDynamic : Index out of range");
return _val[i];
}
When I try to create an instance of the derived class like this (main.cpp):
#include "VectDynamic.h"
int main()
{
VectDynamic<double> v1(5, 2);
return 0;
}
I end up having this error from both classes:
undefined reference to 'VectDynamic<double>::operator[](long)'
Now I know many posts talk about this kind of error, but after hours of searching I couldn't find any reason why it would happen in my case.
I don't think the error would come from the way I includes the files, as it doesn't work either when everything is in a single file.
I've read in this post that it might be due to the the implicit instantiation of the base class that goes on when the derived class is declared since the base class's methods aren't defined yet.
Do you think that is the problem ?
What would be a decent workaround ?
EDIT: Forgot to add the operator[] from the child, added it now (it wasn't causing any error as it was in my code).
Even though Vect<double>::operator[] will never get called, the base vtable must be used for a moment during construction of the derived object and as you declared things, the base vtable has a pointer to that undefined method. That should be solved by adding "=0" (commonly described as "pure virtual") to the declaration of the base method.
Change to
template <typename Elem>
class Vect
{
public:
virtual Elem& operator[](std::ptrdiff_t)=0;
};
From the error it seems pretty clear that you just didn't define VectDynamic<double>::operator[]. If you don't want the [] operator just remove the function declarations. If you do want it, you'll need to implement it.
Note that since it's a template class you can't implement the operator in a non-header source file.
And now that I've said all that, let me just also point out since you don't (correctly) follow the rule of 0, 3, or 5 you'll be leaking memory; is there a reason you aren't using std::vector?
Related
It might be a weird question, but it could be quite handy in my use case.
I have the generic class:
template <typename CGtObj>
class CGtObjectsMap
{
virtual CGtObj* newGtObject(GtId idXML, const CSAXElement *) const { return new CGtObj(idXML); } //!< can be overwritten by MyAbstractClass ;)
virtual void loadFromXml(CSAXElement const* element);
};
with a "quite complex" loadFromXml(CSAXElement const* element) that has at one point:
template <typename CGtObj>
void CGtObjectsMap<CGtObj>::loadFromXml(const CSAXElement *element)
{
...
objPtr = newGtObject(idXML, element);//new CGtObj(idXML);
...
}
A certain class I need to use in that CGtObjectsMap is abstract. That is why I've created the virtual method newGtObject, hoping I could avoid duplicating the whole code of loadFromXml() in a specialization of that class.
But it doesn't compile, and I'm having an error on the template standard definition of newGtObject():
error: invalid new-expression of abstract class type ‘MyAbstractClass’
coming from:
virtual CGtObj* newGtObject(GtId idXML, const CSAXElement *) const { return new CGtObj(idXML); } //!< can be overwritten by MyAbstractClass ;)
although I've specialized it:
template<>
MyAbstractClass *CGtObjectsMap<MyAbstractClass>::newGtObject(GtId idXML, const CSAXElement *element) const
{
MyAbstractClassType type = static_cast<MyAbstractClassType>(element->childValueByName(XML_TYPE).toInt());
return MyAbstractClass::createAction(type, idXML);
}
Is there a way to avoid that compilation issue?
(The specialization is in another file)
I'm currently researching the pimpl idiom and there are very nice tutorials how it could be implement (e.g. here). But i have never seen it implemented as a base template class like this:
#ifndef PIMPL_H
#define PIMPL_H
template <class T>
class Pimpl
{
public:
explicit Pimpl();
explicit Pimpl(T *ptr);
virtual ~Pimpl() = 0;
Pimpl(const Pimpl<T> &other);
Pimpl &operator=(const Pimpl<T> &other);
protected:
T *d_ptr;
};
template<class T>
Pimpl<T>::Pimpl() : d_ptr(new T)
{
}
template<class T>
Pimpl<T>::Pimpl(T *ptr) : d_ptr(ptr)
{
}
template<class T>
Pimpl<T>::~Pimpl()
{
delete d_ptr;
d_ptr = 0;
}
template<class T>
Pimpl<T>::Pimpl(const Pimpl<T> &other) : d_ptr(new T(*other.d_ptr))
{
}
template<class T>
Pimpl<T> &Pimpl<T>::operator=(const Pimpl<T> &other)
{
if (this != &other) {
delete d_ptr;
d_ptr = new T(*other.d_ptr);
}
return *this;
}
#endif // PIMPL_H
Which then could be used in any class you like to pimpl:
#ifndef OBJECT_H
#define OBJECT_H
#include "pimpl.h"
class ObjectPrivate;
class Object : public Pimpl<ObjectPrivate>
{
public:
Object();
virtual ~Object();
/* ... */
};
#endif // OBJECT_H
Currently i'm using it in a small example project (build as a shared library) and the only problem i had, was that MSVC warns about the missing destructor for ObjectPrivate (see C4150). This warning only occurs, because ObjectPrivate is forward declared and therefore not visible to the delete operator in Pimpl::~Pimpl() at compile time.
Does anyone see any sort of problems with this approach? :-)
So there is a now a final version based on the discussion below on GitHub (big thanks to StoryTeller). The repository also contains a simple usage example.
Yes, there are several problems, as I see it.
Your class is essentially a mixin. It's not about dynamic polymorphism, so no-one is ever going to call delete on a pointer to Pimpl<ObjectPrivate>. Drop the virtual destructor. It's introducing overhead that's never going to be required. What you want is static polymorphism only.
You allocate the object with new and release with delete. I won't use your template, because that allocation scheme isn't always appropriate in my applications. You must give a way to customize the allocation scheme in order to make your class actually useful.
Your assignment operator isn't exception safe. If the constructor for T throws, you lose the previously saved data. IMO it's better in this case to use the copy and swap idiom.
The solution to (1) and (2) is to add more template parameters, where the first is for the CRTP. This will allow you to push operations you aren't aware of how to do, onto the class that inherits your mixin. It can override them by defining its own make, unmake and clone. And those will all be bound statically.
template <class Handle, class Impl>
class Pimpl
{
private:
Impl* _make() const
{ return ((Handle const*)this)->make(); }
void _unmake(Impl *p) const
{ ((Handle const*)this)->unmake(p); }
Impl* _clone(Impl *p) const
{ return ((Handle const*)this)->clone(p); }
void swap(Pimpl &other) {
Impl *temp = d_ptr;
d_ptr = other.d_ptr;
other.d_ptr = temp;
}
public:
explicit Pimpl();
~Pimpl();
Pimpl(const Pimpl &other);
Pimpl &operator=(const Pimpl &other);
// fall-backs
static Impl* make() { return new Impl; }
static void unmake(Impl* p) { delete p; }
static Impl* clone(Impl* p) { return new Impl(*p); }
protected:
Impl *d_ptr;
};
template<class Handle, class Impl>
Pimpl<Handle, Impl>::Pimpl() :
d_ptr(_make())
{
}
template<class Handle, class Impl>
Pimpl<Handle, Impl>::~Pimpl()
{
_unmake(d_ptr);
d_ptr = 0;
}
template<class Handle, class Impl>
Pimpl<Handle, Impl>::Pimpl(const Pimpl &other) :
d_ptr(_clone(other.d_ptr))
{
}
template<class Handle, class Impl>
Pimpl<Handle, Impl> &Pimpl<Handle, Impl>::operator=(const Pimpl &other)
{
Pimpl copy(other);
swap(copy);
return *this;
}
Live Example
Now your header can compile cleanly. So long as the destructor for Object isn't defined inline. When it's inline the compiler must instantiate the destructor of the template wherever object.h is included.
If it's defined in a cpp file, after the definition of ObjectPrivate, then the instantiation of ~Pimpl will see the full definition of the private parts.
Further ideas for improvement:
Make the special members protected. It's only the derived Handle class that's supposed to call them, after all.
Add support for move semantics.
But i have never seen it implemented as a base template class
Vladimir Batov did it: https://github.com/yet-another-user/pimpl
Does anyone see any sort of problems with this approach?
You need to take the warning seriously. If your ObjectPrivate actually has a non-trivial destructor (which is as easy as containing a std::string member), you have undefined behavior, and the destructor probably won't get called.
This typically suggests that for some reason, the destructor is instantiated in the wrong place. Make sure that all definitions of all constructors and destructors of the derived class are placed after the full definition of ObjectPrivate. This includes the implicit copy and move constructors, which are probably what triggers the warning in your example code. Yes, this means you have to explicitly declare these special functions (and as a consequence, also the copy and move assignment operators if you want them), but at least you can use a defaulted definition.
I don't know if Vlad's library has the same problem.
Also, nulling out pointers in a destructor is pointless and will probably just get optimized away by some modern compilers.
Modern version that I'm using:
///////////////////////////////
// Header File
template <typename impl_t>
class Pimpl {
public:
Pimpl() = default;
virtual ~Pimpl() = default;
Pimpl(std::shared_ptr<impl_t> handle) : handle(handle) {}
std::shared_ptr<impl_t>
get_handle() const {
return handle;
}
protected:
std::shared_ptr<impl_t> handle;
};
class object_impl;
class object : public Pimpl<object_impl> {
/* whatever constructors you want*/
public:
object(int x);
}
///////////////////////////////
// Cpp File
class object_impl {
public:
object_impl(int x) : x_(x) {}
private:
int x_;
}
object::object(int x) : Pimpl(std::make_shared<object_impl>(x)) {}
As a beginner, I have some problem regarding templates, inheritance and pure virtual functions.
Consider the following, where Probability is an abstract template instantiated as RationalProbability.
Probability.h:
template <class T>
class Probability
{
public:
T value;
//Operator overloading for +
virtual Probability<T>* operator+(const Probability<T>& p);
T getValue() const { return value; }
protected:
Probability(T val) {
value = val;
}
~Probability() {};
};
Probability.cpp : empty
RationalProbability.h:
#include "Probability.h"
class RationalProbability: public Probability<float>
{
public:
RationalProbability(float prob);
virtual ~RationalProbability();
RationalProbability* operator+(const RationalProbability& p);
};
RationalProbability.cpp:
#include "RationalProbability.h"
RationalProbability::RationalProbability(float prob): Probability(prob) {}
RationalProbability::~RationalProbability()
{
}
RationalProbability* RationalProbability::operator+(const RationalProbability& p) {
RationalProbability* rp = new RationalProbability(p.getValue() + this->value);
return rp;
}
I get the following error:
Error:undefined reference to
Probability<float>::operator+(Probability<float> const&)
It is true that there is no function with that exact signature, but RationalProbability implements the template exactly with
RationalProbability: public Probability<float>
If you want a base class to have an abstract function (a virtual function you don't implement) you should say so:
virtual Probability<T>* operator+(const Probability<T>& p) = 0;
The = 0 is what tells the compiler that the member function is an abstract method that must be overridden by sub-classes.
If you don't have that, there must be a definition (implementation) of all virtual functions.
If you look closer at the error message it says that it's Probability<float>::operator+ that is missing, not RationalProbability::operator+.
I also suggest you read and check some canonical operator implementations, especially for the binary arithmetic operators, because you should not return a pointer from the operator+ function. It should return an object by value. Otherwise, how would something like a + b + c work if suddenly the result of one addition was a pointer?
I'll get straight to it: I have a class template that holds a reference and updates info to it:
template<class T>
class Parser {
T& m_ref;
public:
typedef T ValueType;
Parser(T& ref): m_ref(ref) {}
virtual void read(std::istream&);
};
Now, I have another template that creates a new object and updates it using this interface, to do so I have a field that saves the parser.
However, I'd like to use updater to classes that derive from T, which is impossible with poymorphism since Parser<Derived> does not inherit from Parser<Base>.
I created this work-around that uses an intermediate class that inherits from Parser<Base> but updates into a Parser<Derived>:
template<class T>
struct dummy {};
template<class T>
class Creator {
typedef shared_ptr<Parser<T> > ParserPtr;
typedef shared_ptr<T> ValuePtr;
ValuePtr m_output;
ParserPtr m_parser;
template<class ParserType>
class LocalParser : public Parser<T> {
ParserType m_parser;
public:
LocalParser(typename ParserType::ValueType& val):
Parser<T>(/*???*/), //problems start here, I must initialize the base
m_parser(val) {}
void read(std::istream& is) { //use polymorphism to update into some derieved reference
m_parser.read(is);
}
};
public:
Creator(): //Uses Parser<T> as default parser
m_output(new T),
m_parser(new Parser<T>(*m_output)) {}
template<class ParserType>
Creator(dummy<ParserType>) { //Use any parser
auto temp = make_shared(new typename ParserType::ValueType);
m_output = temp;
m_parser = maked_shared(new LocalParser<ParserType>(*temp));
}
virtual ValuePtr read()(std::istream& is) {
m_parser->read(is);
return m_output;
}
};
Basically LocalParser is an intermediate class that inherits from Parser<T> but updates a diffrent reference from the one it's base holds.
The problem here is how to initialize Parser<T>, especially when T is abstract (which is 99% of the time I actually use this class with a derived parser).
My question boils down to "how to define a reference to a (possibly) abstract class that WON'T be used?" (or is there any kind of other work around where I don't define an intermidiate that inherits from Parser<T>).
EDIT: The Parser interface is a separate code I cannot change.
You cannot create an empty reference. A reference must refer to something. That's one of the key differences between a reference and a pointer. In fact, there's a possible solution for you:
T& ref; // error
T& ref = nullref; // no such thing
T* ptr = nullptr; // "empty" pointer!
Another possibly more explicit solution that allows for either a reference or nothing would be to use boost::optional:
boost::optional<T&> opt_ref; // empty optional
opt_ref = some_t;
I've tried implementing a list container,
and decided to move some general functions
like sum() to base class, so that I can
reuse them later in other containers.
All the base support class needs are three
methods empty(), head() and tail.
I can't make those pure virtual because support
class will never be instantiated. But it still
has to use those methods to implement its own
methods like sum().
I tried something like this:
#include <iostream>
using namespace std;
template<typename T>
class StatsSupport {
public:
T sum(void) const {
if (empty()) {
return T(0);
} else {
return head() + tail()->sum;
}
}
// other methods
};
template<typename T>
class List : public StatsSupport<T> {
public:
// constructors etc.
bool empty(void) const {return head_ != NULL;}
const T& head(void) const {return *head_;}
const List<T>& tail(void) const {return *tail_;}
// other methods
private:
T* head_;
List<T> *tail_;
};
But trying to use sum() gets me compilation error
prog.cpp:8:13: error: there are no arguments to 'empty' that depend on a template parameter, so a declaration of 'empty' must be available [-fpermissive]
if (empty()) {
^
for each of empty(), head() and tail().
Any advice?
The problem is that StatsSupport cannot find the empty, head etc. functions because these neither exist in its nor in the global scope.
StatsSupport does not know about the functions that exist in the derived class.
Basically there are two ways to solve this:
Runtime polymorphism, where you add a virtual destructor to StatsSupport and add declarations for empty, head etc. which are pure virtual.
Compile time polymorphism via using CRTP as mentioned in the comments.
I will focus on the latter.
So basically StatsSupport needs to get a way to access functions of the derived class.
This can be done by adding the type of the derived class as template parameter, which is called CRTP:
template<class Derived, typename T>
class StatsSupport {
public:
T sum(void) const {
if (derived()->empty()) {
return T(0);
} else {
return derived()->head() + derived()->tail()->sum;
}
}
// other methods
private:
Derived *derived()
{
return static_cast<Derived*>(this);
}
const Derived *derived() const
{
return static_cast<const Derived*>(this);
}
};
template<typename T>
class List : public StatsSupport<List<T>, T> { // with some changes could be simplified to StatsSupport<List<T>> but this it ouf of scope of this question
I am using a function for derived instead of a member to keep the class const correct.
Of course another alternative would be a different design relying on algorithms. There you move sum and all the other functions of StatsSupport into global namesapce and would then access them like sum(my_container_instance).
A more STL like way would be to use iterators. Then you could use std::accumulate to do the summing.
That's a serious design issue: Your StatSupport defines some general functions, but relies on specifics of its child classes.
So when StatSupport gets compiled, it doesn't even know that there is some head() and tail(). That's why you get the error message
Now imagine that one day you want to define other containers that shall inherit from StatSupport, for example your own Vector or Map, or DataBase. These data structures will not have a head and a tail.
Basically there are two main orientations you may take:
define in your StatSupport some virtual functions for iterating through the data structure.
or better, use in your data structures some iterators (like they exist for standard containers) and define some template functions (sum, average, etc...) that use iterators to browse through your container.
In the latter case, you wouldn't need inheritance to benefit from generic functions.
I might miss the point of the question but will give my 5 cents to it anyway :)
The reasoning behind the solution I show below is, that often people new to OOP (in C++) think that they must use inheritance to get things done.
But especially in C++, this is but one way and often not the best way to achieve composition.
While in the majority of cases, the overhead cost of virtual functions does not really matter, the code below shows a way to yield container expansions without using inheritance and without using virtual functions. The weak point of the approach is that the "container function contract" is only implicitly visible.
template <class _X>
class ContainerTypeA < _X >
{
public:
typedef _X value_type;
typedef ContainerTypeA<_X> container_type;
const _X & Head() const
{
// return head of this containers content.
}
container_type Tail() const
{
// return the tail (all elements after the first element in a new instance.
}
bool IsEmpty() const
{
return true; // return whether or not this container is empty.
}
};
template <class _X>
class ContainerTypeB < _X >
{
public:
typedef _X value_type;
typedef ContainerTypeB<_X> container_type;
const _X & Head() const
{
// return head of this containers content.
}
container_type Tail() const
{
// return the tail (all elements after the first element) in a new instance.
}
bool IsEmpty() const
{
return true; // return whether or not this container is empty.
}
};
// Note: In stead of the class with static member functions, this could
// as well be a namespace with template-functions inside.
template < class _ContainerT >
class ContainerStats<_ContainerT>
{
static _ContainerT::value_type Sum(const _ContainerT & container)
{
// Implement sum - possibly in the recursive way you did in your question.
}
// more expansion functions...
};