-2

I've been teaching myself C++ from a book. I'm getting stuck on the second of four steps. This second section though where I'm told that I have to "Make this class generic so that the sides of the shape may be integer or float."

So far it's a pretty simple program. There are three scripts for it. There is the main.cpp, a shape.cpp, and the shape.h.

The program takes an object name in string, a float in length, and the important one is sides. I have a constructor that puts the object, sides, and length together to create a generic shapes object, which I will upgrade later of course.

But right now is to make it more generic, so I figure that has to do with the template command. It's probably super easy, and I am sorry to waste your time with it. It seems like I have to alter the line Shape shape(object, objectSides, objectLength);, but I am not sure in which way since the other examples seem to indicate that you do it in the header and other class.

main.cpp|35|error: missing template arguments before 'shape'| main.cpp|38|error: 'shape' was not declared in this scope|

main.cpp

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

using namespace std;

int main() {
//Setting variables to 0;
    string object;
    int objectSides = 0;
    int objectSidesTemp = 0;
    float objectLength = 0;
    float objectLengthTemp = 0;

//Taking input for user on object being made.
    cout << "Object to make: ";
    cin >> object;

//Input for sides being inputted. If below 3, asks user again for a valid number.
//Assigns in temp number until within bounds, then assigns to objectSides.
    while (objectSidesTemp < 3){
    cout << "How many sides (Must be 3 or greater): ";
    cin >> objectSidesTemp;
    }
    objectSides = objectSidesTemp;

//Input for length being inputted. If 0 or below, asks user again for a valid number.
//Assigns in temp number until within bounds, then assigns to objectLength.
    while (objectLengthTemp <= 0){
    cout << "Length of sides: ";
    cin >> objectLengthTemp;
    }
    objectLength = objectLengthTemp;

//Creates object of Shape called shape. Inputs the object name, sides, and length.
    Shape shape(object, objectSides, objectLength);

//Displays object specifics.
    shape.display();
}

shape.h

#ifndef SHAPE_H
#define SHAPE_H

#include <string>

using namespace std;

template <class T>
class Shape {

public:
    Shape(string, T, float);
    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();
    T getSides();
    bool setSides(T);
    float getLength();
    void setLength (float);

    float getPerimeter(int, float);
    float getArea (int, float);

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

#endif

shape.cpp

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

using namespace std;

//Constructor of Shape. Inpunts shape, sides, and length.
    Shape::Shape (string shapes, int sides, float length){
        setObject(shapes);
        setSides(sides);
        setLength(length);
    } //End of Shape constructor

//Method to request the amount of sides, returns as an int
//Because there are no lesser than full sides.
    template <class T>
    T Shape::getSides() {
        return sides;
    } //End of function getSides

//Method to set the amount of sides. Return method is a bool.
//If sideNumber is 0 or less in sides, returns a false.
//If sideNumber is greater than 1, returns true.
//Would recommend setting minimum of sides to 3 or greater,
//as anything less is either a shape, a dot, or nothing.
    bool Shape::setSides(int sideNumber) {
        if (sides > 0){
            sides = sideNumber;
            return true;
        }
        else {
            return false;
        }
    } //End of function setSides

//Returns string tied to the shape's object.
//Future in 2D suggests triangle, rectangle, or square.
//Implimented currently as any string.
    string Shape::getObject(){
        return object;
    } //End of function getObject

//Sets input of the string to the variable object.
    void Shape::setObject(string obj){
        object = obj;
    } //End of function setObject

//Retrieves float of length, as length can be numbers with decimals.
    float Shape::getLength(){
        return length;
    } //End of function getLength

//Sets length of the object. Uses void because it doesn't need to return anything.
    void Shape::setLength(float objectLength){
        length = objectLength;
    } //End of function setLength

//Sets area usings 3 sides or 4 sides else returns a 0.
//Returning as float because objectLength is used as a float.
    float Shape::getArea (int objectSides, float objectLength) {
        if (objectSides == 3){
            return (objectSides * objectLength) / 2;
        }
        if (objectSides == 4){
            return (objectLength * objectLength);
        }
//        return objectSides * objectLength;
        return 0;
    } //End of function getArea

//Float return of that parimeter. Multipling sides by length to achieve.
    float Shape::getPerimeter (int objectSides, float objectLength){
        return objectSides * objectLength;
    } //End of function getParimeter.

//Display function shows the Shape's varaibles.
//Uses getParimeter and getArea commands to generate further information of the shape.
    void Shape::display() {
        cout << "Object: " << object << endl;
        cout << "Sides: " << sides << endl;
        cout << "Length: " << length << endl;
        cout << "Perimeter: " << getPerimeter(sides, length) << endl;
        cout << "Area: " << getArea(sides, length) << endl;
    } //End of function display.
Quentin
  • 62,093
  • 7
  • 131
  • 191
Greg
  • 107
  • 2
  • 14
  • Please don't morph your question into another one if it invalidates existing answers. If Vittorio's answer solved the first problem you asked about, mark it as the correct answer. If you have a follow-up question, ask a completely separate question with that. But don't do that here, because your follow-up question [would be a duplicate](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) -- all the info is there. I'm rolling back your edit. – Quentin May 05 '17 at 13:12
  • 1
    @Greg yes it did -- you're now getting a new, entirely unrelated error. Your first error was a syntax error, this one is a linker error. Please read the Q&A I've linked above to solve that one. Don't worry, I see why you would think they are related, but really they're not :) – Quentin May 05 '17 at 13:18

1 Answers1

2

You defined Shape as a class template taking a single template argument T:

template <class T>
class Shape { /* ... */ };

Therefore you need to explicitly specify T when instantiating Shape:

Shape<int> shape(object, objectSides, objectLength);
//    ^^^
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • 3
    Also the entire cpp file is wrong and you can't split a template class in a header and cpp file. – NathanOliver May 05 '17 at 12:31
  • @NathanOliver: correct. I didn't even bother looking at the rest of the code, too much unrelated content. – Vittorio Romeo May 05 '17 at 12:36
  • When you templatize a class you should put the definition and declaration in the header file as pointed out in the first comment. Think about why this is required. It's not arbitrary and will go some way towards understanding templates. – doug May 05 '17 at 14:18