简体   繁体   中英

C++ Polymorphism: Derived class calls Base class virtual funciton instead of the overriden derived one

I have a virtual function printShape() in class Shape and classes Rect,Line and Circle, which override it, then I create an array of Shapes (Shape**) and which holds derived objects, but when I traverse the array every derived object inside the array calls the function printShape() from shape instead the one it has overriden.Here are my Shape and Rectangle classes and the TextManager class where I create and fill the Shape array. Pay no attention to how poorly some other parts of the code are written.

Shape.h:

#ifndef SHAPE
#define SHAPE

class Shape
{
public:
    Shape();
    virtual ~Shape();
    virtual void printShape()const;
    virtual bool isWithin(const Shape*) const;
    virtual void translate(double,double);
public:
    void setFill(const char*);
    const char* getFill() const;

private:
    char fill[10];

};

#endif

Rect.h:

#ifndef RECT
#define RECT

#include "Shape.h"

class Rect :public Shape
{
public:
    Rect();
    Rect(double, double, unsigned int, unsigned int);
    virtual ~Rect();
public:
    virtual bool isWithin(char* name, double x, double y, double ) const;
    virtual bool isWithin(char* name, double x, double y, unsigned int w, unsigned int h) const;
    virtual void translate(double,double);
     void printShape()const;
public:
    void setX(double);
    void setY(double);
    void setWidth(unsigned int);
    void setHeight(unsigned int);
    double getX();
    double getY();
    unsigned int getWidth();
    unsigned int getHeight();

private:
    double x, y;
    unsigned int width, height;
};
#endif

Rect.cpp:

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

void Rect::setX(double x)
{
    this->x = x;
}
void Rect::setY(double y)
{
    this->y = y;
}
void Rect::setWidth(unsigned int w)
{
    this->width = w;
}
void Rect::setHeight(unsigned int h)
{
    this->height = h;
}
double Rect::getX()
{
    return this->x;
}
double Rect::getY()
{
    return this->y;
}
unsigned int Rect::getWidth()
{
    return this->width;
}
unsigned int Rect::getHeight()
{
    return this->height;
}
Rect::Rect()
{
    this->x = 0;
    this->y = 0;
    this->width = 0;
    this->height = 0;
}
Rect::Rect(double X,double Y, unsigned int W, unsigned int H)
{
    setX(X);
    setY(Y);
    setWidth(W);
    setHeight(H);   
}
Rect::~Rect()
{

}

void Rect::printShape()const
{
    std::cout << "rectangle ";
    std::cout
        << this->x << " "
        << this->y << " "
        << this->width << " "
        << this->height << " ";
    std::cout<<getFill(); 
}

bool Rect::isWithin(char* name, double x, double y, unsigned int w, unsigned int h) const
{
    return !((this->x < x) || (this->y < y) || (this->width + this->x >(w + x)) || (this->height + this->y >(h + y)));
}

bool Rect::isWithin(char* name, double x, double y, double rad) const{
    return ((this->x < x + rad) || this->x > x - rad) && (this->y < y + rad) || this->y > y - rad &&
            (this->x+width < x + rad) || (this->x+width > x - rad) && (this->y < y + rad) || (this->y > y - rad) && 
            (this->x + width < x + rad) || (this->x + width > x - rad) && (this->y+height < y + rad) || (this->y+height > y - rad) && 
            (this->x  < x + rad) || (this->x > x - rad) && (this->y + height < y + rad) || (this->y + height > y - rad);
}

void Rect::translate(double vertical, double horizontal)
{
    x += horizontal;
    y += vertical;
}

I have a class ManageText which reads the data from an svg file and fills the array with a function called readFile()

#ifndef MANAGETEXT
#define MANAGETEXT
#include "Shape.h"
#include "Rect.h"
class ManageText
{
public:
    ManageText();
    ~ManageText();
public:
    void readFile(const char*);
    void writeFile(const char*);
public:
    int findSvg(const char*);
    void insertLine(const char* line, int row);
    void removeLine(const char*, int row);
    char* getLineFile(int);
    void setLine(const char*, int);
    void eraseShape(int);
    void printShapes(const char* nameFile) const;
    void translateShapes(double, double);

    void createRect(double x, double y, unsigned int w, unsigned int h, const char* f, int row, const char*);
    void createCircle(double x, double y, double r, const char* f, int row, const char*);
    void createLine(double x1, double y1, double x2, double y2, int row, const char*);

public:
    int getNumberLines();
    void setNumberLines(char* nameFile);
    int getSizeofFile(char* nameFile);
    char* getNameFile();
    char** getText();
    int getShapesSize(const char* fileName) const;
private:
    void clear();
    int getLinesFromFile(const char*);
private:
    char* nameFile;
    char** text;
    int numberLines;
    Shape** shapes;
    int shapesSize;
};
#endif

readFile() in ManageText.cpp:

void ManageText::readFile(const char* nameFile)
{
    std::ifstream file;
    file.open(nameFile, std::ios::in);
    if (!file.is_open())
    {
        std::cout << "error";
        return;
    }
    else
    {
        //read number of figures
        int cntShapes = getShapesSize(nameFile);
        shapes = new Shape*[cntShapes];
        char shape[500000];
        char toNum[15];
        int tmp = 0;
        while (!file.eof())
        {
            file >> shape;
            if (strcmp(shape, "<rect") == 0)
            {
                Rect rect;
                double x;
                double y;
                unsigned int w, h;              
                file >> toNum;
                int nx = strlen(toNum);
                for (int i = 3; i < nx; i++)
                {
                    toNum[i - 3] = toNum[i];
                }
                x = atof(toNum);
                rect.setX(x);

                file >> toNum;
                int ny = strlen(toNum);
                for (int i = 3; i < ny; i++)
                {
                    toNum[i - 3] = toNum[i];
                }
                y = atof(toNum);
                rect.setY(y);

                file >> toNum;
                int nw = strlen(toNum);
                for (int i = 7; i < nw; i++)
                {
                    toNum[i - 7] = toNum[i];
                }
                w = atof(toNum);
                rect.setWidth(w);

                file >> toNum;
                int nh = strlen(toNum);
                for (int i = 8; i < nw; i++)
                {
                    toNum[i - 8] = toNum[i];
                }
                h = atof(toNum);
                rect.setHeight(h);

                file >> toNum;
                int nFill = strlen(toNum);
                for (int i = 6; i < nFill; i++)
                {
                    toNum[i - 6] = toNum[i];
                }
                toNum[nFill - 7] = '\0';
                rect.setFill(toNum);

                shapes[tmp] = &rect;
                tmp++;          
            }

            else if (strcmp(shape, "<circle")==0)
            {
                Circle circle;
                double x, y, r;
                file >> toNum;
                int nx = strlen(toNum);
                for (int i = 4; i < nx; i++)
                {
                    toNum[i - 4] = toNum[i];
                }
                x = atof(toNum);
                circle.setX(x);

                file >> toNum;
                int ny = strlen(toNum);
                for (int i = 4; i < ny; i++)
                {
                    toNum[i - 4] = toNum[i];
                }
                y = atof(toNum);
                circle.setY(y);

                file >> toNum;
                int nr = strlen(toNum);
                for (int i = 3 ; i < nr; i++)
                {
                    toNum[i - 3] = toNum[i];
                }
                r = atof(toNum);
                circle.setRadius(r);

                file >> toNum;
                int nFill = strlen(toNum);
                for (int i = 6; i < nFill; i++)
                {
                    toNum[i - 6] = toNum[i];
                }
                toNum[nFill - 7] = '\0';
                circle.setFill(toNum);

                shapes[tmp] = &circle;
                tmp++;              
            }
            else if (strcmp(shape, "<line") == 0)
            {
                Line line;
                double x1, y1, x2, y2;

                file >> toNum;
                int nx1 = strlen(toNum);
                for (int i = 4; i < nx1; i++)
                {
                    toNum[i - 4] = toNum[i];
                }
                x1 = atof(toNum);
                line.setX1(x1);

                file >> toNum;
                int ny1 = strlen(toNum);
                for (int i = 4; i < ny1; i++)
                {
                    toNum[i - 4] = toNum[i];
                }
                y1 = atof(toNum);
                line.setY1(y1);

                file >> toNum;
                int nx2 = strlen(toNum);
                for (int i = 4; i < nx2; i++)
                {
                    toNum[i - 4] = toNum[i];
                }
                x2 = atof(toNum);
                line.setX2(x2);

                file >> toNum;
                int ny2 = strlen(toNum);
                for (int i = 4; i < ny2; i++)
                {
                    toNum[i - 4] = toNum[i];
                }
                y2 = atof(toNum);
                line.setY2(y2);

                file >> toNum;
                int nFill = strlen(toNum);
                for (int i = 6; i < nFill; i++)
                {
                    toNum[i - 6] = toNum[i];
                }
                toNum[nFill - 7] = '\0';
                line.setFill(toNum);

                shapes[tmp] = &line;
                tmp++;
            }
        }
    }   
}

So my question is why isn't every object from shapes array calling it's own printShapefunction, but the one from the Shape class?

The objects you're calling printShape() on no longer exist

{
    Rect rect;
    ...
    shapes[tmp] = &rect;
} // Oops, rect was local and the reference is no longer valid

By the way, better use std::vector< std::unique_ptr<Shape> > instead of new Shape*[cntShapes]

std::vector< std::unique_ptr<Shape> > shapes;
// ...
{
    std::unique_ptr<Rect> pRect(new Rect);
    // or use std::make_unique<Rect>() if you have C++14
    // ...
    pRect->SetX(x);
    // ...
    shapes.push_back(std::move(pRect));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM