C ++多态:派生类调用基类虚函数而不是重写派生函数

时间:2016-07-02 22:34:08

标签: c++ polymorphism

我在类Shape中有一个虚函数printShape(),并且有一个Rect,Line和Circle类,它会覆盖它,然后我创建一个Shapes数组(Shape **)并保存派生对象,但是当我遍历数组时数组中的每个派生对象都从形状调用函数printShape()而不是它覆盖的函数。这是我的Shape和Rectangle类以及我创建并填充Shape数组的TextManager类。不要注意编写代码的其他部分有多糟糕。

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;
}

我有一个ManageText类,它从svg文件中读取数据,并用一个名为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

ManageText.cpp中的readFile():

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++;
            }
        }
    }   
}

所以我的问题是为什么不是来自shapes数组的每个对象都调用它自己的printShape函数,而是来自Shape类的那个?

1 个答案:

答案 0 :(得分:3)

您正在调用printShape()的对象不再存在

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

顺便说一下,最好使用std::vector< std::unique_ptr<Shape> >代替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));
}