3
votes

It was hard to make the title very clear about the subject, but I will try to explain the context (and there is some of the code down below). Note: I have seen similar questions answered, but they only treated the cases with 1 child class. So they didn't really help in my case, because I have 2 child classes.

Context: I have a parent class Shape that has 2 child: Circle and Square. I will have a vector of Shape objects, but these Shape objects will actually only be either Circle objects or Square objects. I need the Circle and Square classes to have the same parent class so that I can store them both in the same vector.

The trick is that I will need to use the Shape objects in the vector to call methods implemented in either the Circle class or the Square class, therefore, I need to have a "virtual" version of those methods in the parent class Shape.

Here is a simplified part of the code for my classes:

Shape.h :

class Shape{
public:
    std::string getColor();

    virtual int getRadius() = 0; //Method implemented in Circle
    virtual int getHeight() = 0; //Method implemented in Square
    virtual int getWidth() = 0;  //Method implemented in Square

protected:
    std::string color;
};

class Circle : public Shape{
public:
    int getRadius();

private:
    int radius;
};

class Square : public Shape{
public:
    int getHeight();
    int getWidth();

private:
    int height;
    int width;
};

In Shape.cpp I have something like this:

std::string Shape::getColor(){
    return color;
}

int Circle::getRadius(){
    return radius;
}

int Square::getHeight(){
    return height;
}

int Square::getWidth(){
    return width;
}

The errors occurs in the main.cpp when I want to create Circle and Square objects:

Circle *c = new Circle(...);//Error: cannot instantiate abstract class
                            //pure virtual function "Shape::getHeight" has no overrider
                            //pure virtual function "Shape::getWidth" has no overrider


Square *s = new Square(...);//Error: cannot instantiate abstract class
                            //pure virtual function "Shape::getRadius" has no overrider

So it seems like I would need a declaration of "getRadius" in the Square class and a declaration of "getHeight" and "getWidth" in the Circle class...

I tried adding them with virtual, but that makes Circle and Square abstract classes, so I can't create any objects with them.

Is there a way to make this work?

This is my first question posted on stackoverflow. I hope everything is clear. Thanks for the help!

3
You must at least define a body for the pure virtual functions you declared in Shape in each of the derived classes or those classes become abstract base classes and cannot be instantiated.larrylampco
Also, you should inherit from Shape not Shapes.larrylampco
Oups, I fixed it. ThanksJLuc5
No, this attempt at design makes no sense whatsoever, and there is no way to add any. A parent class must only have interface that is common to all child classes, full stop, no ifs or buts or howevers. Look up "is-a relationship".n. 1.8e9-where's-my-share m.
As above, you should rethink your design instead of trying to make badly designed classes to compile. The shape class should only contain members which are common for all shapes. Even an empty base class would be better than your current one.jaho

3 Answers

2
votes

Your virtual methods are not really good candidates for virtual methods because they have specific functionality for one class but no use for the other.

Good example of virtual method would be something implemented by each class but with different functionality or result, like virtual int area() or virtual bool intersects( Shape * otherShape ) and so on.

Anyway, this is how you would get your code compiled (with some extras):

shape:

class Shape{
public:
    std::string getColor();

    Shape() {}
    virtual ~Shape() {}

    virtual int getRadius() { return 0; }  // no pure virtual
    virtual int getHeight() { return 0; }  // no pure virtual
    virtual int getWidth() { return 0; }   // no pure virtual

protected:
    std::string color;
};


class Circle : public Shape {
public:
    Circle( int r )
        : Shape()
        , radius( r )
    {}  

    Circle() : Circle( 0 ) {}
    ~Circle() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    int getRadius() override { return radius; }; 

private:
    int radius;
};

square:

class Square : public Shape {
public:
    Square( int h, int w )
        : Shape()
        , height( h )
        , width( w )
    {}  

    Square() : Square( 0, 0 ) {}
    ~Square() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    int getHeight() override { return height; }
    int getWidth() override { return width; }

private:
    int height;
    int width;
};  

test:

int main() {
    using shapes = std::vector< Shape * >;

    shapes s;
    s.push_back( new Circle( 10 ) );
    s.push_back( new Square() );
    s.push_back( new Square( 1, 3 ) );
    s.push_back( new Circle() );

    for ( Shape * sh : s ) {
        std::cout
            << " r " << sh->getRadius()
            << " h " << sh->getHeight()
            << " w " << sh->getWidth()
            << std::endl;
    }       

    for ( Shape * sh : s ) { delete sh; } s.clear();
}

output:

r 10 h 0 w 0
r 0 h 0 w 0
r 0 h 1 w 3
r 0 h 0 w 0
virtual Circle::~Circle()
virtual Square::~Square()
virtual Square::~Square()
virtual Circle::~Circle()

Here is a better use of virtual methods with area example:

#include <iostream>
#include <vector>

struct Shape {
    Shape() {}
    virtual ~Shape() {}

    virtual double area() = 0;
};

extend with different area implementation:

struct Circle : public Shape {
    Circle( int r )
        : Shape()
        , radius( r )
    {}

    Circle() : Circle( 0 ) {}
    ~Circle() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    virtual double area() override { return radius * radius * 3.14; }

    int radius;
};

struct Square : public Shape {
    Square( int h, int w )
        : Shape()
        , height( h )
        , width( w )
    {}

    Square() : Square( 0, 0 ) {}
    ~Square() { std::cout << __PRETTY_FUNCTION__ << std::endl; }

    virtual double area() override { return height * width; }

    int height;
    int width;
};

test

int main() {
    using shapes = std::vector< Shape * >;

    shapes s;
    s.push_back( new Circle( 1 ) );
    s.push_back( new Square( 1, 1 ) );
    s.push_back( new Square( 2, 3 ) );
    s.push_back( new Circle( 2 ) );

    for ( Shape * sh : s ) {
        std::cout << sh->area() << std::endl;
    }

    for ( Shape * sh : s ) { delete sh; } s.clear();
}

output:

3.14
1
6
12.56
virtual Circle::~Circle()
virtual Square::~Square()
virtual Square::~Square()
virtual Circle::~Circle()
0
votes

I hope you know the difference between pure virtual and just virtual functions. Pure virtual functions are essentially placeholder functions with no body. Your base class of shape is better suited for plain virtual functions, which are functions that can but don't have to be changed in subclasses. Take out the = 0 part in the function declaration to make the functions just plain virtual functions.

0
votes

This should get you headed in the right direction. By making your members not pure virtual you can implement them if you want in the derived classes but you do not have to.

class Shape{
    public:
    std::string getColor();

    virtual int getRadius(); //Method implemented in Circle
    virtual int getHeight(); //Method implemented in Square
    virtual int getWidth();  //Method implemented in Square

protected:
    std::string color;
};

class Circle : public Shape{
public:
    int getRadius();

private:
    int radius;
};

class Square : public Shape{
public:
    int getHeight();
    int getWidth();

private:
    int height;
    int width;
};