This question has already been answered:

Hello, I wrote a template like this. CompositeShape.hpp

class CompositeShape : public Shape { public: CompositeShape(); ~CompositeShape(); template<class T> void addComponent(T shape); void removeComponent(const int index = -1); // if don't input index, then method will remove last component virtual void move(const point_t &posTo) override; virtual void move(const double dx, const double dy) override; virtual void scale(const double coefficient); virtual double getArea() const; rectangle_t getFrameRect() const; int getLength() const; virtual void print(std::string name) const; private: int maxlength_; int length_; Shape **shapes_; void setPosition(); }; 

And it is described in CompositeShape.spp

 #include "CompositeShape.hpp" CompositeShape::CompositeShape() : Shape({0,0}), maxlength_(5), length_(0) { shapes_ = new Shape *[maxlength_]; } CompositeShape::~CompositeShape() { delete[] shapes_; } void CompositeShape::removeComponent(const int index) { //TODO:FIXME if (length_ <= 0) { //TODO: message about exception return; } if (index == -1 && length_ > 0) { shapes_[--length_] = nullptr; if (length_ > 0) { setPosition(); } } if (index < length_ && index >= 0 && length_ > 0) { shapes_[index] = nullptr; for (int i = index; i < length_ - 1; i++) { shapes_[i] = shapes_[i + 1]; } shapes_[--length_] = nullptr; if (length_ > 0) { setPosition(); } } else { // TODO: massege about exception } } void CompositeShape::move(const point_t &posTo) { if (length_ <= 0) { //TODO: massage about exception return; } setPosition(); move(posTo.x - position_.x, posTo.y - position_.y); } void CompositeShape::move(const double dx, const double dy) { if (length_ <= 0) { //TODO: massage about exception return; } setPosition(); position_.x += dx; position_.y += dy; //FIXME: for (int i = 0; i < length_; i++) { shapes_[i]->move(dx, dy); } } void CompositeShape::scale(const double coefficient) { if (length_ <= 0) { //TODO: massage about exception return; } setPosition(); for (int i = 0; i < length_; i++) { shapes_[i]->move({position_.x + coefficient * (shapes_[i]->getPosition().x - position_.x), position_.y + coefficient * (shapes_[i]->getPosition().y - position_.y)});//FIXME: shapes_[i]->scale(coefficient); } } double CompositeShape::getArea() const { if (length_ <= 0) { //TODO: massage about exception return -1; } double area = 0; for (int i = 0; i < length_; i++) { area += shapes_[i]->getArea(); } return area; } rectangle_t CompositeShape::getFrameRect() const { if (length_ <= 0) { //TODO: massage about exception return {{0, 0}, -1, -1}; } double left = shapes_[0]->getPosition().x - shapes_[0]->getFrameRect().width / 2; double right = shapes_[0]->getPosition().x + shapes_[0]->getFrameRect().width / 2; double top = shapes_[0]->getPosition().y + shapes_[0]->getFrameRect().height / 2; double bottom = shapes_[0]->getPosition().y - shapes_[0]->getFrameRect().height / 2; for (int i = 1; i < length_; i++) { if ((shapes_[i]->getPosition().x - shapes_[i]->getFrameRect().width / 2) < left) { left = shapes_[i]->getPosition().x - shapes_[i]->getFrameRect().width / 2; } if ((shapes_[i]->getPosition().x + shapes_[i]->getFrameRect().width / 2) > right) { right = shapes_[i]->getPosition().x + shapes_[i]->getFrameRect().width / 2; } if ((shapes_[i]->getPosition().y + shapes_[i]->getFrameRect().height / 2) > top) { top = shapes_[i]->getPosition().y + shapes_[i]->getFrameRect().height / 2; } if ((shapes_[i]->getPosition().y - shapes_[i]->getFrameRect().height / 2) < bottom) { bottom = shapes_[i]->getPosition().y - shapes_[i]->getFrameRect().height / 2; } } return {{(left + (right - left) / 2), (bottom + (top - bottom) / 2)}, (right - left), (top - bottom)}; } void CompositeShape::setPosition() { if (length_ > 0) { position_ = getFrameRect().pos; } } int CompositeShape::getLength() const { return length_; } void CompositeShape::print(std::string name) const { std::cout << name << std::endl; for (int i = 0; i < length_; i++) { shapes_[i]->print("from composite shape"); } } template <class T> void CompositeShape::addComponent(T shape) { //TODO:FIXME if (std::is_base_of<Shape,T>::value){ std::cout << "Exception: can add not Shape element" << std::endl; return; } if (length_ < maxlength_) { Shape *shape1 = new T(shape); shapes_[length_] = shape1; length_++; setPosition(); } else { Shape **shapes1 = shapes_; shapes_ = new Shape *[maxlength_ + 5]; for (int i = 0; i < maxlength_; i++) { shapes_[i] = shapes1[i]; } delete[] shapes1; maxlength_ += 5; addComponent(shape); } } 

Moreover, if you write such a year in main

  #include "CompositeShape.hpp" # include "rectangle.hpp" Rectangle rect1 = Rectangle({0, 0}, 10, 10); 

then we get an error

  CompositeShape compositeShape; compositeShape.addComponent(rect1); undefined reference to void CompositeShape::add component <Rectangle>(Rectangle) 

How can this be fixed?

Reported as a duplicate by Abyx c ++ Apr 20 '17 at 6:01 pm

A similar question was asked earlier and an answer has already been received. If the answers provided are not exhaustive, please ask a new question .

  • I fixed the question - marsofandrew

1 answer 1

Cannot implement templates in .cpp files.

This -

 template <class T> void CompositeShape::addComponent(T shape) { ... 

transfer to CompositeShape.hpp .

Think for yourself, taking the place of the compiler - for what type of T should the compiler instantiate this template to roll it into an object file in the form of a called function? If it is called somewhere somewhere else?

The second option is to force the template to be instantiated with the type you know about , but not the compiler - it will know about it when compiling the file with main() . But this is not a good solution - if you change something, a new type is added or something else, you will get the same problem. So just write all the template implementations in the included files ...