Greg
Greg

Reputation: 107

C++ explicit instantiation of non-template type

I'm reading a book about C++. I'm still fairly to it, but I'm still trying to get the nitty gritty things done. This section involves inheritance, and the goal is to make a shape class, then build onto it with first two dimensional shapes, and then three dimensional shapes building off of two dimensional shapes.

So far I've been able to get all the way up and completing the two dimensional shapes. The functions in there work fine. I've now moved onto three dimensional shapes, and that's where I'm running into a bit of a problem.

The book says to implement a system that allows for length, height, and for three dimensional width to be either ints or floats, so I have put a template into them to do that. This is where I think I'm running into issues.

I did copy and past the two dimensional class into the three dimensional class and try to complete it from there. Then I ran it to a bit of the problem.

When I try to compile, I get two main errors.

error: 'ThreeD' is not a class template error: explicit instantiation of non-template type 'ThreeD'

I think is the smallest piece that needs to be submitted with relevant information. Keeping in mind, main.cpp, shape.h, shape.cpp, twod.h, and twod.cpp do work as is, but I've included the full headers rather than the full others cpps.

Any help that you could provide would be great.

I've put the ThreeD.cpp at the top since that is where the error is coming from.

I don't think it's a duplicate of "Why can templates only be implemented in the header file?" because the code works fine with the TwoD class, just not the ThreeD class.

ThreeD.cpp

#include <iostream>
#include <string>
#include "shape.h"
#include "TwoD.h"

using namespace std;

template class ThreeD<int>;
template class ThreeD<float>;


    template <class T>
    ThreeD<T>::ThreeD (string oobj, int osides, T olength, T oheight, T owidth)
        : TwoD<T>(oobj, osides, olength, oheight)
    {
        setObject(obj);
        setSides(sides);
        setLength(length);
        setHeight(height);
        setWidth(owidth);
    } //End of TwoD constructor

template <class T>
int ThreeD<T>::getSides() {
    return sides;
} //End of function getSides

main.cpp

#include <iostream>
#include "shape.h"
#include "TwoD.h"
#include "ThreeD.h"

using namespace std;

int main() {


TwoD<float> triangle("Triangle", 3, 3, 3);

ThreeD<float> cube("Cube", 6, 3, 3, 3);
}

Shape.h

#ifndef SHAPE_H
#define SHAPE_H

#include <string>

using namespace std;

//Implimenting template <class T> as a means to have the sides
//variable become either a float or an int.
template <class T>
class Shape {

public:
    Shape(string, int, T);
//    void setObject(string); //Used to ensure constructor works
    virtual void setObject(string) = 0;
//Used setObject as virtual function since constructor uses it to
//Make the object using the setObject function.
    string getObject();
    int getSides();
    bool setSides(int);
    float getLength();
    void setLength (T);

    float getPerimeter(string, T);
    float getArea (string, T);

    void display();
private:
    string object;
    int sides;
    T length;
};

#endif

Shape.cpp

#include <iostream>
#include <string>
#include "shape.h"

using namespace std;

//Telling the compiler template class of Shape which versions for T to
//expect either int or float.
template class Shape<int>;
template class Shape<float>;

//Constructor of Shape. Inputs shape, sides, and length.
    template <class T>
    Shape<T>::Shape (string shapes, int sides, T length){
        setObject(shapes);
        setSides(sides);
        setLength(length);
    } //End of Shape constructor

TwoD.h

#ifndef TWOD_H
#define TWOD_H

#include <string>
#include "shape.h"

using namespace std;

//Implimenting template <class T> as a means to have the sides
//variable become either a float or an int.
template <class T>
class TwoD : public Shape<T>
{

public:
    TwoD(std::string, int, T, T);
    void setObject(string); //Used to ensure constructor works
//    virtual void setObject(string) = 0;
//Used setObject as virtual function since constructor uses it to
//Make the object using the setObject function.
    string getObject();
    int getSides();
    bool setSides(int);
    T getLength();
    void setLength (T);
    T getHeight();
    void setHeight (T);

    float getPerimeter(string, T, T);
    float getArea (string, T, T);

    void display();
private:
    string object;
    int sides;
    T length;
    T height;
};

#endif

TwoD.cpp

#include <iostream>
#include <string>
#include "shape.h"
#include "TwoD.h"

using namespace std;

//Telling the compiler template class of TwoD which versions for T to
//expect either int or float.
template class TwoD<int>;
template class TwoD<float>;

//Constructor of TwoD. Inputs TwoD, sides, and length.
    template <class T>
    TwoD<T>::TwoD (string obj, int sides, T length, T height)
        : Shape<T>(obj, sides, length)
    {
        setObject(obj);
        setSides(sides);
        setLength(length);
        setHeight(height);
    } //End of TwoD constructor

ThreeD.h

#ifndef THREED_H
#define THREED_H

#include <string>
#include "shape.h"
#include "TwoD.h"

using namespace std;

//Implimenting template <class T> as a means to have the sides
//variable become either a float or an int.
template <class T>
class ThreeD : public TwoD<T>
{

public:
    ThreeD(std::string, int, T, T, T);
    void setObject(std::string); //Used to ensure constructor works
//    virtual void setObject(string) = 0;
//Used setObject as virtual function since constructor uses it to
//Make the object using the setObject function.
    string getObject();
    int getSides();
    bool setSides(int);
    T getLength();
    void setLength (T);
    T getHeight();
    void setHeight (T);

    T getWidth();
    void setWidth (T);

    float getPerimeter(string, T, T, T);
    float getArea (string, T, T, T);

    void display();
private:
    std::string object;
    int sides;
    T length;
    T height;
    T width;
};

#endif

Upvotes: 1

Views: 1745

Answers (1)

M.M
M.M

Reputation: 141574

In ThreeD.cpp you need:

#include "ThreeD.h"

Without that, the line template class ThreeD<int>; makes no sense to the compiler, because ThreeD has not been declared.

Upvotes: 2

Related Questions