Home > OS >  Why can't I use the inherited class when I called abstract class?
Why can't I use the inherited class when I called abstract class?

Time:12-26

Problem:

My code is about using abstract class Shape and creating 3 shapes Rectangle, Circle, and Triangle. I used a factory and singleton design pattern in the ShapeFactory class. When I read the file, I called the method getInstance() and pointed to the createShape method. After that, I pointed to the derived class and called the setter to set some variables. The problem is it's said that my abstract class doesn't have any setter members.

Tries:

I have tried to create all the setter to the Shape class and it worked but it violates object-oriented programming rules so I'm trying to do other ways. I have also tried to search for the errors but it doesn't meet my needs.

The error:

oop3.cpp: In member function 'void ShapeFileIO::readFile(std::__cxx11::string, std::vector<std::shared_ptr<Shape> >&)':
oop3.cpp:259:28: error: 'using element_type = class Shape' {aka 'class Shape'} has no member named 'setWidth'; did you mean '_width'?
                 rectangle->setWidth(stod(width));
                            ^~~~~~~~
                            _width
oop3.cpp:260:28: error: 'using element_type = class Shape' {aka 'class Shape'} has no member named 'setHeight'; did you mean '_height'?
                 rectangle->setHeight(stod(height));
                            ^~~~~~~~~
                            _height
oop3.cpp:270:25: error: 'using element_type = class Shape' {aka 'class Shape'} has no member named 'setRadius'; did you mean '_radius'?
                 circle->setRadius(stod(radius));
                         ^~~~~~~~~
                         _radius
oop3.cpp:284:27: error: 'using element_type = class Shape' {aka 'class Shape'} has no member named 'setSide1'; did you mean '_side1'?
                 triangle->setSide1(stod(side1));
                           ^~~~~~~~
                           _side1
oop3.cpp:285:27: error: 'using element_type = class Shape' {aka 'class Shape'} has no member named 'setSide2'; did you mean '_side2'?
                 triangle->setSide2(stod(side2));
                           ^~~~~~~~
                           _side2
oop3.cpp:286:27: error: 'using element_type = class Shape' {aka 'class Shape'} has no member named 'setSide3'; did you mean '_side3'?
                 triangle->setSide3(stod(side3));
                           ^~~~~~~~
                           _side3

My code:

This is my code that gets errors:

auto rectangle = ShapeFactory::getInstance()->createShape("Rectangle");
                rectangle->setWidth(stod(width));
                rectangle->setHeight(stod(height));

auto circle = ShapeFactory::getInstance()->createShape("Circle");
                circle->setRadius(stod(radius));

auto triangle = ShapeFactory::getInstance()->createShape("Triangle");
                triangle->setSide1(stod(side1));
                triangle->setSide2(stod(side2));
                triangle->setSide3(stod(side3));

This is my factory class:

class ShapeFactory {
public:
    map<string, shared_ptr<Shape>> _prototypes;
private:
    inline static shared_ptr<ShapeFactory> _instance = nullptr;
    ShapeFactory() {
        auto rec = make_shared<Rectangle>();
        auto cir = make_shared<Circle>();
        auto tri = make_shared<Triangle>();

        _prototypes.insert({"Rectangle", rec});
        _prototypes.insert({"Circle", cir});
        _prototypes.insert({"Triangle", tri});
    }
public:
    static shared_ptr<ShapeFactory> getInstance() {
        if (_instance == nullptr) {
            auto temp = new ShapeFactory();
            _instance = shared_ptr<ShapeFactory>(temp);
        }
        return _instance;
    }

    shared_ptr<Shape> createShape(string shape) {
        auto it = _prototypes[shape];
        auto result = it->clone();
        return result;
    }
};

This is my abstract class:

class Shape {
protected:
    string _shape;

public:
    Shape() { _shape = ""; }
    Shape(string shape) { _shape = shape; }
    virtual ~Shape() {}

public:
    void setShape(string shape) { _shape = shape; }
    virtual string magicWord() = 0;
    virtual shared_ptr<Shape> clone() = 0;
};

This is my ShapeFileIO class:

class ShapeFileIO {
public:
    void readFile(string fileName, vector<shared_ptr<Shape>>& shapes) {
        ifstream inFile;
        inFile.open(fileName);
        
        if (!inFile) {
            cout << "Unable to open file";
            exit(1);
        }
        string line, width, height, radius, side1, side2, side3;
        while (!inFile.eof()) {          
            getline(inFile, line);
            stringstream ss(line);
            getline(ss, width, '=');
            getline(ss, width, ',');
            getline(ss, height, '=');
            getline(ss, height);
            if (line.find("Rectangle") != string::npos) {
                auto rectangle = ShapeFactory::getInstance()->createShape("Rectangle");
                rectangle->setWidth(stod(width));
                rectangle->setHeight(stod(height));
                shapes.push_back(rectangle);
            }

            getline(inFile, line);
            stringstream ss2(line);
            getline(ss2, radius, '=');
            getline(ss2, radius);
            if (line.find("Circle") != string::npos) {
                auto circle = ShapeFactory::getInstance()->createShape("Circle");
                circle->setRadius(stod(radius));
                shapes.push_back(circle);
            }

            getline(inFile, line);
            stringstream ss3(line);        
            getline(ss3, side1, '=');
            getline(ss3, side1, ',');
            getline(ss3, side2, '=');
            getline(ss3, side2, ',');
            getline(ss3, side3, '=');
            getline(ss3, side3);
            if (line.find("Triangle") != string::npos) {
                auto triangle = ShapeFactory::getInstance()->createShape("Triangle");
                triangle->setSide1(stod(side1));
                triangle->setSide2(stod(side2));
                triangle->setSide3(stod(side3));
                shapes.push_back(triangle);
            }
        }
        cout << "File read successfully" << endl << endl;
        inFile.close();
    }
};

CodePudding user response:

Your problem is easy to explain, less easy to correct. Look at this line:

auto rectangle = ShapeFactory::getInstance()->createShape("Rectangle");

Here we have this auto that's supposed to make life easier, but sometimes it hides the real problems. Namely: what is the type of rectangle here? To settle this, let's look at the declaration of createShape:

shared_ptr<Shape> ShapeFactory::createShape(string shape); 

So, this function returns shared_ptr<Shape>. Thus, your rectangle is of type shared_ptr<Shape>, too, and in this expression

rectangle->setWidth(stod(width));

you tell the compiler to access the member setWidth of class Shape. The compiler is obliged to protest and refuse to do so, because Shape is a base class with no method named setWidth.

How to fix this is a different story. The easiest way would be to use some form of the dynamic cast on the pointer returned by createShape,

auto base_ptr = ShapeFactory::getInstance()->createShape("Rectangle");
auto rectangle = std::dynamic_pointer_cast<Rectangle> (base_ptr); 

One problem with it is that it is ugly and there's danger that you'll need to resort to dynamic casts in several other parts of the program. That would be weird and undesired. I don't use factories etc., you'll need to find the solution that suits your needs yourself.

See also: c Inheritance and shared pointers

PS. Next time when you ask on SO, please try to provide a Minimal, reproducible example - you would have had a clear, precise answer minutes after posting the question.

  • Related