首页 文章

虚函数“形状”赋值

提问于
浏览
-6

我似乎无法让我的气缸类正确执行其打印和音量功能 . 以下是赋值的说明:设计一个名为Shape的类,它是一个抽象基类 . Shape有两个纯虚函数,printShapeName和print .

Shape包含另外两个虚函数,area和volume,每个函数都有一个返回零值的默认实现 .

Point类从Shape继承这些实现(点的面积和体积均为零) . Point具有x和y坐标私有成员 .

Class Circle派生自具有公共继承的Point . 圆的体积为0.0,因此不会覆盖基类成员函数体积 . 圆形具有非零区域,因此在此类中覆盖区域功能 . 写入get和set函数以返回并为Circle指定新的半径 .

Class Cylinder派生自Circle并具有公共继承 . A Cylinder的面积和体积与Circle的面积和体积不同,因此该类别中的面积和体积函数都被覆盖 . 写入get和set函数以返回高度并指定新的高度 .

创建一个点,一个圆和一个圆柱然后打印结果 .

//
//  Shape.hpp
//  HW6_VirtualFunctions
//
//  Created by Aviv Fedida on 11/25/17.
//  Copyright © 2017 Aviv Fedida. All rights reserved.
//

#ifndef Shape_hpp
#define Shape_hpp

#include <stdio.h>
#include <iostream>
#include <cmath>
using namespace std;

class Shape {
protected:  // protected members
    double width, height, radius, pi, x, y;
public:
    void setWidth(double a);    // prototype for width setter
    void setHeight(double b);   // prototype for height setter
    void setX(double c);
    void setY(double d);
    void setRad(double r);
    void setPi(double p);
    double getWidth() { // get width to return only
        return width;
    }
    double getHeight() { // get height to return only
        return height;
    }
    double getX() {
        return x;
    }
    double getY() {
        return y;
    }
    double getRad() {
        return radius;
    }
    double getPi() {
        return pi;
    }
    // Create public virtual functions
    virtual void printShapeName() = 0; // pure virtual for printing shape's name
    virtual void print(double a, double b) = 0; // pure virtual print function
    virtual double area() {  // virtual area function returns default null
        return 0;
    }
    virtual double volume() {  // virtual default volume function returns null
        return 0;
    }
};  // END BASE CLASS -------------------------------------------------------------------------------------

class Point: public Shape {
    // x & y coordinates needed for a point
public:
    // Prototypes for print & set functions
    void printShapeName();
    void print(double a, double b);
    };  // end first derived class ------------------------------------------------------------------------

class Circle: public Point {
public:
    //  Protoypes for print functions
    void printShapeName();
    void print(double r, double p);
    //  Prototypes for area & volume functions
    double area(double r, double p);
};  // end second derived class ----------------------------------------------------------------------------

class Cylinder: public Circle {
public:
    double area(double r, double p);
    void printShapeName();
    double volume(double r, double p, double h);
    void print(double r, double p, double h);
}; // end third and final derived class --------------------------------------------------------------------------

//  Some definitions outside classes
//--------------------------------------------------    BEGIN   -----------------------------------------------------------
//  Shape base class setter functions defined
void Shape::setWidth(double a) {
    width = a;
}
void Shape::setHeight(double b) {
    height = b;
}
void Shape::setX(double c) {
    x = c;
}
void Shape::setY(double d) {
    y = d;
}
void Shape::setRad(double r) {
    radius = r;
}
void Shape::setPi(double p) {
    p = 3.1416;
    pi = p;
}

void Point::printShapeName() {   // Print name of class
    cout << "Point " << endl;
}
void Point::print(double a, double b) {   // Print values within class
    cout << "(" << a << "," << b << ")" << endl;
}

void Circle::printShapeName() {
    cout << "Circle " << endl;
}
//  Circle area function defined
double Circle::area(double r, double p) {
    double area;
    area = p*(pow(r,2));
    return area;
}
void Circle::print(double r, double p) {
    cout << "Area of circle is: " << area(r, p) << endl;
    cout << "Volume of circle is: " << volume() << endl;
}

void Cylinder::printShapeName() {
    cout << "Cylinder " << endl;
}
double Cylinder::area(double r, double p) {
    double area;
    area = 2*p*r;
    return area;
}
double Cylinder::volume(double r, double p, double h) {
    double volume;
    volume = p*(pow(r,2))*h;
    return volume;
}
void Cylinder::print(double r, double p, double h) {
    cout << "Area of cylinder is: " << area(r, p) << endl;
    cout << "Volume of cylinder is: " << volume(r, p, h) << endl;
}



#endif /* Shape_hpp */

//
//  main.cpp

#include <iostream>
#include "Shape.hpp"
#include "Shape.cpp"

using namespace std;

int main() {
    double pi = 3.1416; // Variable for pi
    //  Instantiate class objects
    Point guard;
    Circle k;
    Cylinder cid;
    //  Instantiate pointers to class objects
    Shape *pptr;
    Shape *kptr;
    Shape *cptr;
    //  Assign memory of objects to pointer variables
    pptr = &guard;
    kptr = &k;
    cptr = &cid;
    //  Call objects via pointers and print members
    pptr->printShapeName();
    pptr->print(5,6);
    cout << '\n';
    kptr->printShapeName();
    kptr->print(9,pi);
    cout << '\n';
    cptr->printShapeName();
    cptr->getHeight();
    cptr->setHeight(8);
    cptr->print(5,pi);
    return 0;
}

如果我尝试在Cylinder类的print函数中添加第三个height参数,则会出错 . 它最终使用我的Circle类定义 .

1 回答

  • 0

    如果你还没有找到答案, cptr->print(5,pi); 用2个参数调用 print . Circle 有一个2参数 print Cylinder 有一个3参数 print . 由于 CylinderCircle 继承了2参数 print ,因此 Cylinder 打印为 Circle .

    JakeFreeman的评论可能没有帮助,但它完全正确 . 让我们尝试使其有用,而无需重复教科书的几个章节 .

    你已经碰到了两个主要的OO概念:封装和多面体 .

    封装是这里的主要问题,处理它解决了多态性问题 .

    Cylinder 对象应代表一个且仅代表一个Cylinder . 应该将半径和高度存储在其中 . 调用函数并传入半径和高度在意识形态上是错误的 . 在 Cylinder 上执行方法时,它应该已经知道它的半径和高度 . volume 方法不应该使用任何参数,因为计算卷所需的所有内容都应该已知 . 这允许任何形状具有相同的 volume 界面,即使支持界面的方法对于每个形状可能是不同的 .

    完全相同的逻辑适用于区域 .

    接下来,并非所有形状都具有半径,因此 Shape 应该对半径一无所知 . 或高度 . 或深度 . 也许形状知道一些锚定点,但这是关于所有形状应该知道的 .

    同样地, print 应该不需要参数,除了可能是要打印到的IO流的引用,因为IOstream并不是人们通常期望Cylinder知道或关心的内容 .

    一个唠叨:为什么要传递pi?如果你有一个pi不是常数的系统,你就有一个奇怪的系统 .

    修改形状:

    class Shape {
    protected:  // protected members
        static constexpr double pi = 3.1459 // add more precision as needed
        double x, y;
    public:
        Shape (double posx, double posy): x(posx), y(posy)
        { // set up as much as you can in a constructor because otherwise you always 
          // have to look over your shoulder and test, "Did the object get properly 
          // initialized?"
        }
        void setX(double c)
        {
             if (c is within logical bounds)
             { // because a setter that does not protect the object is no better for
               encapsulation than a public member variable
                 x = c;
             }
        }
        void setY(double d);
        {
             if (d is within logical bounds)
             {
                 x = d;
             }
        }
        double getX() {
            return x;
        }
        double getY() {
            return y;
        }
        // Create public virtual functions
        virtual void printShapeName() = 0; // pure virtual for printing shape's name
        virtual void print() = 0; // pure virtual print function
        virtual double area() {  // virtual area function returns default null
            return 0;
        }
        virtual double volume() {  // virtual default volume function returns null
            return 0;
        }
    };
    

    注意没有设置任何形状的骨头 . 在一个正方形上强制 setRadius 函数只是简单的愚蠢 .

    另请注意,这消除了 Point 的需要,但这是一件好事 . 圆是一种点吗?没有 . 圆圈是一个点 . 除极少数例外情况外,除非存在所谓的is-a关系,否则不要延长 . 正方形是一个专门的矩形 . 矩形是一种特殊的形状 . 但这两点都不重要 .

    我建议将 setXsetY 分组到同时执行这两个操作的 setPosition 中,因为稍后您可以更轻松地将其转换为原子事务 .

    修订 Circle

    class Circle: public Shape {
    protected:
        double radius;
    public:
        Circle(double posx, double posy, double rad): Shape(posx, posy), radius(rad)
        {
        }
        void setRadius(double rad)
        {
            if (rad makes sense)
            {
                radius = rad;
            }
        }
        double getRadius()
        {
            return radius;
        }
        //  Protoypes for print functions
        void printShapeName();
        virtual void print();
        double area();
    };
    
    double Circle::area() {
        return  pi*radius*radius; // note on pow. It can be very slow. For simple 
                                  // exponents just multiply
    }
    void Circle::print() {
        cout << "Area of circle is: " << area() << '\n';
        // also shy away from `endl` in favour of a raw end of line.
        // endl flushes the stream to the underlying media, also very expensive,
        // so something best done when you have to or you have nothing better to do. 
        cout << "Volume of circle is: 0\n";
    }
    

    Circle 添加了需要添加到 Shape 的内容 . 而已 . 没什么 . Cylinder 也会这样做 . 它是一个圆圈加 heightheight 的访问器,使用 Circlearea 方法和 height 的卷计算,它自己的 area 方法来计算其表面区域,另一个打印方法打印出它的统计数据

    附录:如果你的编译器支持它,那么它应该利用 override 关键字 . 如果编译器找到一个标记为override的方法并且它没有覆盖任何东西,那么你会得到一个很好的干净错误消息,而不是一堆调试 .

相关问题