使用dynamic_cast检测派生类时指针出错

时间:2015-07-07 08:02:56

标签: c++ oop inheritance polymorphism dynamic-cast

我想就我面临的问题提供一些帮助。

我使用带有类Shape和Circle(从形状派生)的polymorph程序进行了继承。所以我有一些像这样的代码

的main.cpp

Shape* shape = new (nothrow) Shape[size]();
input_circle(shape);
show_circle_area(shape);

和main.cpp中的程序

void show_circle_area(Shape *mshape){
    int i;
    sort(mshape,mshape+totshape,sortByArea);
    cout << "CIRCLE" << endl;
    for (i=0;i<totshape;i++)
        if (dynamic_cast<Circle*> (mshape[i]))
            cout << mshape[i].getWidth() << " " << mshape[i].getArea() << " " << mshape[i].getPerimeter() << endl;
}

当我运行这个程序时,我总是遇到这个错误:

main2.cpp: In function 'void output_circle(Shape*)':
main2.cpp:66:39: error: cannot dynamic_cast '*(mshape + ((sizetype)(((unsigned int)i) * 40u)))' (of type 'class Shape') to type 'class Circle*' (source is not a pointer)
   if (dynamic_cast<Circle*> (mshape[i]))
                                       ^

任何人都可以帮我解决这个问题吗?

main.cpp(已更新)

#include "Shape.h"
#include "Circle.h"
#include "Rectangle.h"
#include "Square.h"
#include <fstream>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <iomanip>
#include <limits>
#include <typeinfo>

using namespace std;
const int size = 200;
int totshape = 0;

// INPUT FROM FILE

void input_circle(Shape* mshape[]){
    ifstream file;
    int i;
    double r;
    file.open("circle.txt");
    while (file >> r){
        Circle* crl = new (nothrow) Circle(r);
        mshape[totshape]=crl;
        totshape++;
    }
    file.close();
}

void input_rectangle(Shape* mshape[]){
    ifstream file;
    int i;
    double w,h;
    file.open("rectangle.txt");
    while (file >> w >> h){
        Rectangle* rec = new (nothrow) Rectangle(w,h);
        mshape[totshape]=rec;
        totshape++;
    }
    file.close();
}

void input_square(Shape* mshape[]){
    ifstream file;
    int i;
    double s;
    file.open("square.txt");
    while (file >> s){
        Square* sqr = new (nothrow) Square(s);
        mshape[totshape]=sqr;
        totshape++;
    }
    file.close();
}

//OUTPUT TO FILE

void output_circle(Shape *mshape[]){
    int i;
    ofstream file;
    file.open("outcircle.txt");
    file << "radius\tarea\tperimeter" << endl;
    for (i=0;i<totshape;i++){
        if (dynamic_cast<Circle*> (mshape[i]))
            file << mshape[i]->getWidth() << "\t" << mshape[i]->getArea() << "\t" << mshape[i]->getPerimeter() << endl;
    }
    file.close();
}

void output_rectangle(Shape *mshape[]){
    int i;
    ofstream file;
    file.open("outrectangle.txt");
    file << "width\theight\tarea\tperimeter" << endl;
    for (i=0;i<totshape;i++){
        if (dynamic_cast<Rectangle*> (mshape[i]))
            file << mshape[i]->getWidth() << "\t" << mshape[i]->getHeight() << "\t" << mshape[i]->getArea() << "\t" << mshape[i]->getPerimeter() << endl;
    }
    file.close();
}

void output_square(Shape *mshape[]){
    int i;
    ofstream file;
    file.open("outsquare.txt");
    file << "sisi\tarea\tperimeter" << endl;
    for (i=0;i<totshape;i++){
        if (dynamic_cast<Square*> (mshape[i]))
            file << mshape[i]->getWidth() << "\t" << mshape[i]->getArea() << "\t" << mshape[i]->getPerimeter() << endl;
    }
    file.close();
}

//SORTING STL FOR AREA AND PERIMETER

bool sortByArea(Shape lhs[], Shape rhs[]) { 
    return lhs->getArea() < rhs->getArea(); 
}

bool sortByPerimeter(Shape lhs[], Shape rhs[]){
    return lhs->getArea() < rhs->getArea();
}

//SHOW DATA SORT BY AREA

void show_shape_area(Shape *shape[]){
    int i;
    sort(shape,shape+totshape,sortByArea);
    cout << "ALL SHAPE" << endl;
    for (i=0;i<totshape;i++)
        cout << shape[i]->getWidth() << " " << shape[i]->getWidth() << " " << shape[i]->getArea() << " " << shape[i]->getPerimeter() << endl;
}

void show_circle_area(Shape *mshape[]){
    int i;
    sort(mshape,mshape+totshape,sortByArea);
    cout << "CIRCLE" << endl;
    for (i=0;i<totshape;i++)
        if (dynamic_cast<Circle*> (mshape[i]))
            cout << mshape[i]->getWidth() << " " << mshape[i]->getArea() << " " << mshape[i]->getPerimeter() << endl;
}

void show_rectangle_area(Shape *mshape[]){
    int i;
    sort(mshape,mshape+totshape,sortByArea);
    cout << "RECTANGLE" << endl;
    for (i=0;i<totshape;i++)
        if (dynamic_cast<Rectangle*> (mshape[i]))
            cout << mshape[i]->getWidth() << " " << mshape[i]->getHeight() << " " << mshape[i]->getArea() << " " << mshape[i]->getPerimeter() << endl;
}

void show_square_area(Shape *mshape[]){
    int i;
    sort(mshape,mshape+totshape,sortByArea);
    cout << "SQUARE" << endl;
    for (i=0;i<totshape;i++)
        if (dynamic_cast<Square*> (mshape[i]))
            cout << mshape[i]->getWidth() << " " << mshape[i]->getArea() << " " << mshape[i]->getPerimeter() << endl;
}

//SHOW DATA SORT BY PERIMETER

void show_shape_perimeter(Shape *shape[]){
    int i;
    sort(shape,shape+totshape,sortByPerimeter);
    cout << "ALL SHAPE" << endl;
    for (i=0;i<totshape;i++)
        cout << shape[i]->getWidth() << " " << shape[i]->getWidth() << " " << shape[i]->getArea() << " " << shape[i]->getPerimeter() << endl;
}

void show_circle_perimeter(Shape *mshape[]){
    int i;
    //Shape * tempshape;
    sort(mshape,mshape+totshape,sortByPerimeter);
    cout << "CIRCLE" << endl;
    for (i=0;i<totshape;i++)
        //cout << "masuk for" << endl;
        //tempshape=&mshape[i];
        if (dynamic_cast<Circle*> (mshape[i])){
            cout << mshape[i]->getWidth() << " " << mshape[i]->getArea() << " " << mshape[i]->getPerimeter() << endl;
            //cout << "masuk" << endl;
        }
}

void show_rectangle_perimeter(Shape *mshape[]){
    int i;
    sort(mshape,mshape+totshape,sortByPerimeter);
    cout << "RECTANGLE" << endl;
    for (i=0;i<totshape;i++)
        if (dynamic_cast<Rectangle*> (mshape[i]))
            cout << mshape[i]->getWidth() << " " << mshape[i]->getHeight() << " " << mshape[i]->getArea() << " " << mshape[i]->getPerimeter() << endl;
}

void show_square_perimeter(Shape *mshape[]){
    int i;
    sort(mshape,mshape+totshape,sortByPerimeter);
    cout << "SQUARE" << endl;
    for (i=0;i<totshape;i++)
        if (dynamic_cast<Square*> (mshape[i]))
            cout << mshape[i]->getWidth() << " " << mshape[i]->getArea() << " " << mshape[i]->getPerimeter() << endl;
}

//ADD DATA
void add_circle(Shape *mshape[]){
    int input;
    cout << endl << "Masukkan jari-jari : ";
    while (!(cin >> input) || input < 0) // <<< note use of "short circuit" logical operation here
    {
        cout << "Input tidak valid" << endl;
        cout << "Masukkan jari-jari : ";
        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // NB: preferred method for flushing cin
    }
    Circle* crl = new (nothrow) Circle(input);
    mshape[totshape]=crl;
    totshape++;
}

void add_rectangle(Shape *mshape[]){
    int inwidth, inheight;
    cout << endl << "Masukkan panjang : ";
    while (!(cin >> inwidth) || inwidth < 0) // <<< note use of "short circuit" logical operation here
    {
        cout << "Input tidak valid" << endl;
        cout << "Masukkan panjang : ";
        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // NB: preferred method for flushing cin
    }
    cout << endl << "Masukkan lebar : ";
    while (!(cin >> inheight) || inheight < 0 || !(inheight < inwidth)) // <<< note use of "short circuit" logical operation here
    {
        cout << "Input tidak valid" << endl;
        cout << "Masukkan lebar : ";
        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // NB: preferred method for flushing cin
    }
    Rectangle* rec = new (nothrow) Rectangle(inwidth,inheight);
    mshape[totshape]=rec;
    totshape++;
}

void add_square(Shape *mshape[]){
    int input;
    cout << endl << "Masukkan sisi : ";
    while (!(cin >> input) || input < 0) // <<< note use of "short circuit" logical operation here
    {
        cout << "Input tidak valid" << endl;
        cout << "Masukkan sisi : ";
        cin.clear();
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // NB: preferred method for flushing cin
    }
    Square* sqr = new (nothrow) Square(input);
    mshape[totshape]=sqr;
    totshape++;
}

//DELETE DATA


//MAIN PROGRAM

int main(){
    Shape* shape[size];

    input_circle(shape);
    input_rectangle(shape);
    input_square(shape);

    show_shape_area(shape);
    show_shape_perimeter(shape);

    show_circle_area(shape);
    show_circle_perimeter(shape);

    show_rectangle_area(shape);
    show_rectangle_perimeter(shape);

    show_square_area(shape);
    show_square_perimeter(shape);

    //add_circle(shape);
    //show_circle_area(shape);

    //add_rectangle(shape);
    //show_rectangle_area(shape);

    //add_square(shape);
    //show_square_area(shape);

    output_circle(shape);
    output_rectangle(shape);
    output_square(shape);

    return 0;
}

1 个答案:

答案 0 :(得分:1)

你的问题在这里:

mshape[totshape]=crl;

此作业只是将crl内的“形状部分”复制到mshape[totshape],因此mshape[totshape]仍然是形状,而不是圆形。

为了解决您的问题,请使用Shape *指针数组而不是Shape值:

Shape* shape[size]; // we should write this as size is a const

而且,您的input_***()功能:

void input_circle(Shape* mshape[]){
    ifstream file;
    int i;
    double r;
    file.open("circle.txt");
    while (file >> r){
        Circle* crl = new Circle(r);
        mshape[totshape]=crl;
        totshape++;
    }
    file.close();
}

请注意,函数原型已更改,请为其他函数执行此操作,并使用mshape[i]->foo代替mshape[i].foo

现在的演员是:if (dynamic_cast<Circle*> (mshape[i])){

在我们使用指针之前,不要忘记在结束之前释放内存:

for (int i = 0; i < totshape; i++) delete mshape[i];

此删除会强制您使Shape的析构函数为虚拟:

class Shape {
    public:
        virtual ~Shape() {...}
}

否则,Circle,Rectangle ...的析构函数将不会被调用。