面向对象(作业)

发布于:2024-11-29 ⋅ 阅读:(21) ⋅ 点赞:(0)

10.类和对象

1.立方体类的实现

立方体类Box的实现,完成计算体积、计算表面积、输出结果等功能。其中给定的主函数为:

int  main( ){
    float ab;
    cin>>ab;
    Box  obj;
    obj.seta( ab );
    obj.getvolume( );
    obj.getarea( );
    obj.disp( );
    return 0;
}

输入格式:

立方体的边长,可以是float类型的数据。

输出格式:

立方体的体积和表面积,中间用一个空格隔开,末尾换行。

输入样例:

3

输出样例:

27 54

代码

#include<iostream>
using namespace std;

class Box{
    float bian;

    public:

    void seta(float ab){
        bian=ab;
    }

    void getvolume(){
        cout<<bian*bian*bian<<" ";
    }

    void getarea(){
        cout<<bian*bian*6;
    }

    void disp(){
        cout<<'\n';
    }
};

int  main( ){
    float ab;
    cin>>ab;
    Box  obj;
    obj.seta( ab );
    obj.getvolume( );
    obj.getarea( );
    obj.disp( );
    return 0;
}

2. 通过指针,输出对象数组的数据

设计一个类,主函数中建立一个对象数组,输入5个学生数据(学号、成绩),用对象指针指向数组首元素,输出5个学生的数据。

输入格式:

输入5个学生数据(学号、成绩),学号为不超过10000的正整数,成绩为0-100的正整数。

输出格式:

按顺序输出学生的学号和成绩,每行显示一个学生的信息。

输入样例:

在这里给出一组输入。例如:

101 90
102 80
103 70
104 60
105 50

输出样例:

在这里给出相应的输出。例如:

101 90
102 80
103 70
104 60
105 50

代码

#include <iostream>
using namespace std;

// 定义学生结构体
typedef struct {
    int id;       // 学号
    int score;    // 成绩
} Student;

int main() {
    Student students[5];  // 创建一个包含5个学生的数组
    Student *ptr = students;  // 定义一个指向Student类型的指针,并指向数组的首元素

    
    for (int i = 0; i < 5; i++) {
        printf("请输入学生%d的学号和成绩(用空格分隔): ", i + 1);
        cin>>students[i].id>>students[i].score;
    }

    
    for (int i = 0; i < 5; i++) {
        cout<<ptr[i].id<<ptr[i].score<<endl;
    }

    return 0;
}

3计算捐款总量

这里需要设计一个捐款人类Donator及一个相关函数getMaxName( ),Donator类中包含捐款人的姓名及其捐款额,其部分代码如下:

class Donator{
    private:
        string name; //捐款人姓名
        float money; //捐款金额,单位:元        
    public:
        void setName(string _name);
        void setMoney(float _money);
        string getName(){return name;}
        float getMoney(){return money;}
        

请根据题意将代码补充完整,以输出一批捐款人来到前后的捐款总金额,以及本批次捐款人中捐款最高者的姓名,题目保证捐款人数不少于1人。

裁判测试程序样例:

输入样例:

第一行为捐款人数及当前的捐款总额,第二行开始每行为一个捐款人的姓名和个人捐款金额。

3 28.5
Xiaoyu 12
Mike 81.5
Joey  50

输出样例:

输出本批次捐款人到达前后的捐款总额,及本批次中捐款最高者的姓名。

total:28.5
total:172
Mike

代码

#include <iostream>
using namespace std;

class Donator{
    private:
        string name;
        float money; //单位:元        
    public:
        void setName(string _name);
        void setMoney(float _money);
        string getName(){return name;}
        float getMoney(){return money;}
        friend string getMaxName(Donator *dt,int n);
        friend  void read(Donator dt[],int n);
        static float totalMoney;
        static void printTotal(){cout<<"total:"<<totalMoney<<endl;}

};

       float Donator::totalMoney=0;
void Donator::setName(string _name)
{
    name=_name;
}

void Donator::setMoney(float _money)
{
    money=_money;
    totalMoney+=_money;
}

string getMaxName(Donator *dt,int n)
{
    float max=0;
    Donator *Max=dt;
    for(int i=0;i<n;i++,dt++)
    {
        if(max<dt->getMoney())
        {
            max=dt->getMoney();
            Max=dt;
        }
    }
    return Max->getName();
}

//读取n个捐款人的姓名和捐款额 
void read(Donator dt[],int n){
    string name;
    float money;
    for(int i=0;i<n;i++){
        cin>>name>>money;
        dt[i].setName(name);
        dt[i].setMoney(money);
    }
}
 
int main(){
    int n;
    cin>>n; 输入本批次将参与的捐款人数
    cin>>Donator::totalMoney; //输入目前已有的捐款总额 
    Donator::printTotal();
    Donator d[n];
    read(d,n);
    Donator::printTotal();
    cout<<getMaxName(d,n)<<endl;//输出本批次中捐款最高者姓名 
    return 0;     

扩展

在C++中,static关键字有多种用途,但当它用于类成员时,主要目的是改变该成员变量的存储方式和访问权限。static关键字用于Donator类的两个成员:totalMoneyprintTotal方法。下面是为什么需要使用static的详细解释:

1. static float totalMoney;

  • 存储方式static成员变量属于类本身,而不是类的某个对象。这意味着,不管创建了多少个Donator对象,它们都共享同一个totalMoney变量。因此,totalMoney可以用来跟踪所有Donator对象捐款的总和。

  • 访问权限:由于totalMoney是静态的,它可以通过类名直接访问(如Donator::totalMoney),也可以通过对象访问(尽管通常不推荐这样做,因为这会让人误以为它是非静态的)。在您的代码中,setMoney方法通过totalMoney+=_money;更新了这个静态变量,从而确保了所有捐款都被累加起来。

2. static void printTotal(){cout<<"total:"<<totalMoney<<endl;}

  • 存储方式:和静态数据成员一样,静态成员函数也属于类本身,而不是某个对象。因此,它们可以在没有创建类对象的情况下被调用(尽管在您的代码中,printTotal是通过对象或类名调用的)。

  • 访问权限:静态成员函数只能访问类的静态成员变量和其他静态成员函数。这是因为静态成员函数不与任何特定的对象实例关联。在printTotal函数中,它访问了静态成员变量totalMoney来打印捐款总额。

  • 用途:由于printTotal不依赖于任何特定的Donator对象,它是一个非常适合作为静态成员函数的方法。它提供了一个方便的接口来查询所有Donator对象捐款的总额。

4设计一个People类

设计一个People 类,该类的数据成员有姓名、年龄、身高、体重和人数,其中人数为静态数据成员,成员函数有构造函数、显示和显示人数。其中构造函数由参数姓名、年龄、身高和体重来构造对象;显示函数用于显示人的姓名、年龄、身高和体重;显示人数函数为静态成员函数,用于显示总的人数。

输入格式:

按姓名、年龄、身高和体重依次输入每个人的信息
已exit结束
zhang 18 180 70
li 20 160 50
exit

输出格式:

输出总人数,例如
2

输入样例:

在这里给出一组输入。例如:

zhang 18 180 70
li 20 160 50
exit

输出样例:

在这里给出相应的输出。例如:

2

代码

#include <string>
using namespace std;

#define MMAX 100

class People {
    string name;
    int age, height, weight;

public:
    static int num;
    People(string a = "", int b = 0, int c = 0, int d = 0)
        : name(a), age(b), height(c), weight(d) {}

    void display() const {
        cout << name << " " << age << " " << height << " " << weight << endl;
    }

    static void show(const People* p, int count) {
        for (int i = 0; i < count; i++) {
            p[i].display();
        }
    }

    static void shownum() {
        cout << num << endl;
    }
};

int People::num = 0;

int main() {
    People p[MMAX];
    string name;
    int age, height, weight;
    while (cin >> name && name != "exit") {
        cin >> age >> height >> weight;
        p[People::num++] = People(name, age, height, weight);
    }
    //People::show(p, People::num);
    People::shownum();
    return 0;
}

5求两点之间距离

定义一个Point类,有两个数据成员:x和y, 分别代表x坐标和y坐标,并有若干成员函数。
定义一个函数Distance(), 用于求两点之间的距离。

输入格式:

输入有两行:
第一行是第一个点的x坐标和y坐标;
第二行是第二个点的x坐标和y坐标。

输出格式:

输出两个点之间的距离,保留两位小数。

输入样例:

0 9
3 -4

输出样例:

13.34

代码

#include <iostream>  
#include <cmath>  
#include <iomanip>
using namespace std;  
  
class Point {  
public:
    double x, y;  

    Point(double x_val = 0, double y_val = 0) : x(x_val), y(y_val) {}  
};  
  
double Distance(const Point& p1, const Point& p2) {  
    return sqrt(pow(p2.x - p1.x, 2) + pow(p2.y - p1.y, 2));  
}  
  
int main() {  
    Point p1, p2;  
    cin >> p1.x >> p1.y;  
    cin >> p2.x >> p2.y;  
    double dist = Distance(p1, p2);   
    cout << fixed << setprecision(2) << dist << endl;  
    return 0;  
}

11.继承和派生

1狗的继承

完成两个类,一个类Animal,表示动物类,有一个成员表示年龄。一个类Dog,继承自Animal,有一个新的数据成员表示颜色,合理设计这两个类,使得测试程序可以运行并得到正确的结果。

扩展

在C++中,const关键字用于指定变量的值在初始化后不能被修改,或者用于指定成员函数不会修改对象的状态(即不会修改成员变量的值,除非这些成员变量被声明为mutable)。

  1. 成员函数后的const
    const出现在成员函数的参数列表之后(即函数声明的末尾),它表示该成员函数是一个常量成员函数。这意味着,该成员函数不能修改其所属对象的任何成员变量(除非这些成员变量被声明为mutable)。

    int getAge() const { return age; }
    void show() const {
    cout << "age:" << age << endl;
    }

    这两个成员函数都被声明为const,因此它们都不能修改age成员变量的值(假设age是该类的成员变量)。这些函数可以被称为常量成员函数只读成员函数因为它们不会改变对象的状态。

  2. 成员变量前的const(虽然您的代码中没有直接展示,但通常也是常见的用法):
    const出现在成员变量声明之前时,它表示该成员变量是一个常量成员变量,其值在初始化后不能被修改。

请注意,即使成员函数被声明为const,它仍然可以调用其他常量成员函数,并且可以通过指针或引用来访问常量数据成员。但是,它不能调用非常量成员函数,也不能修改任何成员变量的值(除非这些成员变量被声明为mutable)。

代码

#include<bits/stdc++.h>
using namespace std;

class Animal{
    protected:
    int age;

    public:
    Animal(int num):age(num){}

    int getAge() const{return age;}
    void show() const{
        cout<<"age:"<<age<<endl;
    }
    
};

class Dog:public Animal{
    string color;

    public:
    Dog(int num,const string &col):Animal(num),color(col){}

    void showInfor() const{
        Animal::show();
            cout<<"color:"<<color<<endl;
    }
};

int main(){
    Animal ani(5);
    cout<<"age of ani:"<<ani.getAge()<<endl;
    Dog dog(5,"black");
    cout<<"infor of dog:"<<endl;
    dog.showInfor();
}

2定义基类Point和派生类Circle,求圆的周长.

定义基类Point(点)和派生类Circle(圆),求圆的周长。Point类有两个私有的数据成员float x,y;Circle类新增一个私有的数据成员半径float r和一个公有的求周长的函数getCircumference();主函数已经给出,请编写Point和Circle类。

#include <iostream>
#include<iomanip>
using namespace std;
//请编写你的代码
int main()
{
    float x,y,r;
    cin>>x>>y>>r;
    Circle c(x,y,r);
    cout<<fixed<<setprecision(2)<<c.getCircumference()<<endl;
    return 0;
}

输入格式:

输入圆心和半径,x y r中间用空格分隔。

输出格式:

输出圆的周长,小数点后保留2位有效数字。

输入样例:

1 2 3

输出样例:

在这里给出相应的输出。例如:

Point constructor called
Circle constructor called
18.84
Circle destructor called
Point destructor called

代码

#include<iostream>
#include<iomanip>
#define PI 3.14
using namespace std;
class Point {
protected:
    float X, Y;
public:
    Point() {}
    Point(float x, float y) :X(x), Y(y) {
        cout << "Point constructor called" << endl;
    }
    ~Point() {
        cout << "Point destructor called" << endl;
    }
};
class Circle :public Point {
    float R;
public:
    float c;
    Circle() {}
    Circle(float x, float y, float r) :Point(x, y), R(r) {
        cout << "Circle constructor called" << endl;
    };
    ~Circle() {
        cout << "Circle destructor called" << endl;
    }
    float getCircumference();
};
float Circle::getCircumference() {
    c = PI * R * 2;
    return c;
}
int main()
{
    float x, y, r;
    cin >> x >> y >> r;
    Circle c(x, y, r);
    cout << fixed << setprecision(2) << c.getCircumference() << endl;
    return 0;
}

3学生CPP成绩计算

给出下面的人员基类框架:

class Person
{

protected:

     string name;
     int age;

public:

     Person();      
     Person (string p_name, int p_age);
     void display () {cout<<name<<“:”<<age<<endl;}

};

建立一个派生类student,增加以下成员数据:

int ID;//学号
float cpp_score;//cpp上机成绩
float cpp_count;//cpp上机考勤
float cpp_grade;//cpp总评成绩
     //总评成绩计算规则:cpp_grade = cpp_score * 0.9 + cpp_count * 2;

增加以下成员函数:

student类的无参构造函数

student类的参数化构造函数//注意cpp_grade为上机成绩和考勤的计算结果

void print()//输出当前student的信息

                 //其中cpp_grade输出保留一位小数
                //输出格式为ID name cpp_grade

生成上述类并编写主函数,根据输入的学生基本信息,建立一个学生对象,计算其cpp总评成绩,并输出其学号、姓名、总评成绩。

输入格式: 测试输入包含若干测试用例,每个测试用例占一行(学生姓名 学号 年龄 cpp成绩 cpp考勤)。当读入0时输入结束,相应的结果不要输出。

输入样例:

Bob 10001 18 75.5 4

Mike 10005 17 95.0 5

0

输出样例:

10001 Bob 75.9

10005 Mike 95.5

代码

#include<bits/stdc++.h>
using namespace std;

class  Person
{
   protected:
     string name;
     int age;
    
 public:
     Person(): name(""), age(0) {}      
Person(string p_name, int p_age) : name(p_name), age(p_age) {}
    void display () {cout<<name<<" ";}
};

class Student:public Person{
    int id;//学号
float cpp_score;//cpp上机成绩
float cpp_count;//cpp上机考勤
float cpp_grade;//cpp总评成绩

    public:
    Student():Person(), id(0), cpp_score(0.0), cpp_count(0.0), cpp_grade(0.0) {} 
    Student(string name,int age,int id,float score,float count)
    :Person(name,age),id(id),cpp_score(score),cpp_count(count){
         cpp_grade = cpp_score * 0.9 + cpp_count * 2;  
    }

    void print(){
        cout <<id<< " "<<name << " "<<fixed << setprecision(1) << cpp_grade << endl;  
    }
};
int main(){
    string name;  
    int id, age;  
    float cpp_score, cpp_count;  
  
    while (cin >> name && name != "0") {  
        cin >> id>> age >> cpp_score >> cpp_count;  
  
        Student student(name, age, id, cpp_score, cpp_count);  
          student.print();  
}
}

12.多态

1.表彰优秀学生(多态)

学期结束,班主任决定表彰一批学生,已知该班学生数在6至50人之间,有三类学生:普通生,特招运动员,学科专长生,其中学科专长生不超过5人。

主函数根据输入的信息,相应建立GroupA, GroupB, GroupC类对象。

GroupA类是普通生,有2门课程的成绩(均为不超过100的非负整数);

GroupB类是特招运动员,有2门课程的成绩(均为不超过100的非负整数),1次运动会的表现分,表现分有:A、B、C、D共4等。

GroupC类是学科专长生,有5门课程的成绩(均为不超过100的非负整数)。

表彰人员至少符合以下3个条件中的一个:

(1)2门课程平均分在普通生和特招运动员中,名列第一者。

a.该平均分称为获奖线。

b.存在成绩并列时,则全部表彰,例如某次考试有2人并列第1,则他们全部表彰。

(2)5门课程平均分达到或超过获奖线90%的学科专长生,给予表彰。

(3)2门课程平均分达到或超过获奖线70%的特招运动员,如果其运动会表现分为A,给予表彰。

输入格式:每个测试用例占一行,第一项为类型,1为普通生,2为特招运动员,3为学科专长生, 输入0表示输入的结束。第二项是学号,第三项是姓名。对于普通生来说,共输入5项,第4、5项是课程成绩。对于特招运动员来说,共输入6项,第4、5项是课程成绩,第6项是运动会表现。对于学科专长生来说,共输入8项,第4、5、6、7、8项是课程成绩。

输出时,打印要表彰的学生的学号和姓名。(输出顺序与要表彰学生的输入前后次序一致)

函数接口定义:

以Student为基类,构建GroupA, GroupB和GroupC三个类

输入样例:

1 001 AAAA 96 80
2 009 BBB 82 75 A
1 007 CC 100 99
3 012 CCCC 97 95 90 99 93
1 003 DDD 62 50
1 022 ABCE 78 92
2 010 FFF 45 40 A
3 019 AAA 93 97 94 82 80
0

输出样例:

009 BBB
007 CC
012 CCCC

扩展

  1. virtual void display()=0;

    • virtual 关键字表示该函数是一个虚函数,意味着它可以在派生类(Derived Class)中被重写(Override)。虚函数允许通过基类指针或引用来调用派生类中的实现,这是多态性的基础。
    • void 表示该函数没有返回值。
    • =0 表示该函数是一个纯虚函数(Pure Virtual Function)。纯虚函数没有自己的实现,它强制要求任何继承该基类的派生类必须提供该函数的实现。包含至少一个纯虚函数的类被称为抽象基类,这样的类不能被实例化

代码

#include<iostream>
#include <string>
using namespace std;

 class Student
{
public:
    Student(string cnum, string cname, int cs1, int cs2)
    {
        num = cnum;
        name = cname;
        s1 = cs1;
        s2 = cs2;
    }
    virtual void display() = 0;
protected:
    string name, num;
    int s1, s2;
 
 
};
static float maxAvg = 0;
 
class GroupA :public Student
{
public:
    GroupA(string cnum, string cname, int cs1, int cs2) :Student(cnum, cname, cs1, cs2)
    {
        float avg = (s1 + s2) / 2.0;
        if (avg > maxAvg)maxAvg = avg;
    }
    void display()
    {
        if ((s1 + s2) / 2.0 == maxAvg)
            cout << num << " " << name << endl;
    }
};
class GroupB :public Student
{
public:
    GroupB(string cnum, string cname, int cs1, int cs2, char cbxf) :Student(cnum, cname, cs1, cs2)
    {
        bxf = cbxf;
 
        float avg = (s1 + s2) / 2.0;
        if (avg > maxAvg)maxAvg = avg;
    }
    void display()
    {
 
        if ((s1 + s2) / 2.0 == maxAvg || (s1 + s2) / 2.0 >= maxAvg * 0.7 && bxf == 'A')
        {
 
            cout << num << " " << name << endl;
        }
    }
private:
    char bxf;
};
class GroupC :public Student
{
private:
    int s3, s4, s5;
public:
    GroupC(string cnum, string cname, int cs1, int cs2, int cs3, int cs4, int cs5) :Student(cnum, cname, cs1, cs2)
    {
        s3 = cs3;
        s4 = cs4;
        s5 = cs5;
 
    }
    void display()
    {
        float avg = (s1 + s2 + s3 + s4 + s5) / 5.0;
        if (avg >= 0.9 * maxAvg)
        {
            cout << num << " " << name << endl;
        }
    }
};

int main()
{
    const int Size=50;
    string num, name;
    int i,ty,s1,s2,s3,s4,s5;
    char gs;
    Student *pS[Size];
    int count=0;
    for(i=0;i<Size;i++){
        cin>>ty;
        if(ty==0) break;
        cin>>num>>name>>s1>>s2;
        switch(ty){
             case 1:pS[count++]=new GroupA(num, name, s1, s2); break;
             case 2:cin>>gs; pS[count++]=new GroupB(num, name, s1,s2, gs); break;
             case 3:cin>>s3>>s4>>s5; pS[count++]=new GroupC(num, name, s1,s2,s3,s4,s5); break;
        }            
    }
    for(i=0;i<count;i++) {
        pS[i]->display();
        delete pS[i];
    }
    return 0;
}

2.上课铃响之后 (虚基数)

如本章开篇所述,当小学里的上课铃响之后,学生(Student)、教师(Teacher)和校长(Principal)会对同一个消息表现出不同的行为。请设计Person、Student、Teacher以及Principal类,合理安排他们之间的继承关系并将所有类的bellRing()及析构函数设计为虚函数,使得下述代码可以正常执行并产生期望的执行结果。

输入样例:

输出样例:

School bell rings...
I am a student learning in classroom.
I am a teacher teaching in classroom.
I am the principal inspecting in campus.
A student object destroyed.
A teacher object destroyed.
A principal object destroyed.

扩展

在C++中,override关键字是C++11引入的一个特性,用于明确表示一个成员函数重写了基类中的虚函数。虽然它不是必须的,但使用它有几个好处:

  1. 编译时检查:如果你声明了一个函数为override,但实际上并没有正确地重写基类中的虚函数(比如因为函数签名不匹配),编译器会报错。这可以帮助你更早地发现错误。

  2. 代码可读性:使用override关键字可以让其他阅读你代码的人清楚地知道这个成员函数是重写了一个基类中的虚函数。这增加了代码的可读性和可维护性。

  3. 避免意外覆盖:在某些情况下,你可能无意中覆盖了基类中的某个函数(比如因为函数名和参数列表恰好相同),而override关键字可以帮助避免这种情况,因为它要求你必须明确地重写基类中的虚函数。

回到你的问题,override关键字不一定要写,但强烈建议你在重写基类虚函数时使用它。这样做可以提高代码的安全性和可维护性。

所以,对于

void bellRing() override {
cout << "I am a student learning in classroom." << endl;
}

这里使用override是一个好的实践,因为它确保了bellRing函数确实是在重写基类中的某个虚函数bellRing。如果基类中没有名为bellRing的虚函数,或者签名不匹配,编译器将会报错,从而帮助你及时发现和解决问题。

代码
 

#include <iostream>
using namespace std;

class Person {
public:
    virtual void bellRing() = 0;
    virtual ~Person() {
    }
};

class Student : public Person {
public:
    void bellRing() override {
        cout << "I am a student learning in classroom." << endl;
    }
    ~Student() override {
        cout << "A student object destroyed." << endl;
    }
};

class Teacher : public Person {
public:
    void bellRing() override {
        cout << "I am a teacher teaching in classroom." << endl;
    }
    ~Teacher() override {
        cout << "A teacher object destroyed." << endl;
    }
};

class Principal : public Person {
public:
    void bellRing() override {
        cout << "I am the principal inspecting in campus." << endl;
    }
    ~Principal() override {
        cout << "A principal object destroyed." << endl;
    }
};

int main() {
    cout << "School bell rings..." << endl;
    Person* persons[3] = {new Student(),new Teacher(),new Principal()};
    persons[0]->bellRing();
    persons[1]->bellRing();
    persons[2]->bellRing();
    for (auto i=0;i<3;i++)
        delete persons[i];
    return 0;
}

3. 用虚函数计算各种图形的面积

定义抽象基类Shape,由它派生出五个派生类:Circle(圆形)、Square(正方形)、Rectangle( 长方形)、Trapezoid (梯形)和Triangle (三角形),用虚函数分别计算各种图形的面积,输出它们的面积和。要求用基类指针数组,每一个数组元素指向一个派生类的对象。PI=3.14159f,单精度浮点数计算。

输入格式:

输入在一行中,给出9个大于0的数,用空格分隔,分别代表圆的半径,正方形的边长,矩形的宽和高,梯形的上底、下底和高,三角形的底和高。

输出格式:

输出所有图形的面积和,小数点后保留3位有效数字。

输入样例:

12.6 3.5 4.5 8.4 2.0 4.5 3.2 4.5 8.4

输出样例:

578.109

扩展

虚函数允许通过基类指针或引用来调用派生类中的实现,这是多态性的基础。

方式一:

Base* basePtrArray[2];
// 声明派生类对象的指针
Derived1* d1Ptr = new Derived1(); // 使用new在堆上分配内存
Derived2* d2Ptr = new Derived2(); // 同样在堆上分配内存
// 将派生类对象的指针赋值给基类指针数组
basePtrArray[0] = d1Ptr;
basePtrArray[1] = d2Ptr;
// ... 使用basePtrArray进行操作 ...
// 不要忘记在适当的时候释放内存
delete d1Ptr;
delete d2Ptr;

在这个例子中,d1Ptr 和 d2Ptr 是指向 Derived1 和 Derived2 对象的指针,这些对象是在堆上通过 new 关键字分配的。然后,这些指针被赋值给 basePtrArray 数组的元素。

方式二:

在C++中,如果你有一个基类指针数组,并且每个数组元素都指向一个派生类的对象,这通常意味着你正在使用多态性。多态性允许你通过基类指针引用来调用派生类中的重写函数。以下是如何创建和使用这样的基类指针数组的示例:

首先,定义一个基类和一个或多个派生类:

#include <iostream>
#include <vector>
// 基类
class Base {
public:
virtual void show() const {
std::cout << "Base class show function." << std::endl;
}
virtual ~Base() = default; // 虚析构函数,确保正确删除派生类对象
};
// 派生类
class Derived1 : public Base {
public:
void show() const override {
std::cout << "Derived1 class show function." << std::endl;
}
};
class Derived2 : public Base {
public:
void show() const override {
std::cout << "Derived2 class show function." << std::endl;
}
};

然后,你可以创建一个基类指针数组(或使用std::vector<Base*>更现代和安全的方式)来存储指向派生类对象的指针:

int main() {
// 使用原生数组
Base* basePtrArray[2];
// 或者使用std::vector
// std::vector<Base*> basePtrVector;
// 创建派生类对象,并通过基类指针数组存储它们的地址
Derived1 d1;
Derived2 d2;
basePtrArray[0] = &d1;
basePtrArray[1] = &d2;
// 或者使用std::vector添加元素
// basePtrVector.push_back(&d1);
// basePtrVector.push_back(&d2);
// 通过基类指针调用派生类的show函数(多态性)
for (int i = 0; i < 2; ++i) {
basePtrArray[i]->show();
}
// 注意:这里的d1和d2是在栈上分配的,所以它们会在main函数结束时自动销毁。
// 如果你在堆上分配这些对象(使用new),则需要确保在适当的时候删除它们(使用delete)。
// 如果使用std::vector,则可以在不再需要时遍历vector并删除每个指针指向的对象,
// 但请注意,这通常不是管理动态内存的最佳方式(考虑使用智能指针)。
return 0;
}

在这个例子中,basePtrArray是一个基类指针数组,它存储了指向Derived1Derived2对象的指针。当我们通过basePtrArray[i]->show()调用show函数时,由于show在基类中被声明为virtual,并且在派生类中被override,所以调用的是派生类中的show函数,这就是多态性的体现。

代码 

#include <iostream>
#include<iomanip>
using namespace std;
class CShape 
{
    public:
    virtual double Area() { };
};
class CRectangle:public CShape
{
    public:
        double w,h;
        virtual double Area(){return w * h;}
};
class CCircle:public CShape
{
    public:
        double r;
        virtual double Area(){return 3.14159 * r * r ;}

};
class CTriangle:public CShape
{
    public:
        double a,b;
        virtual double Area(){
        return a*b/2;
    }
};
class Square:public CShape
{
    public:
        double w;
        virtual double Area(){return w*w;}
};
class Trapezoid:public CShape
{
    public:
        double d,c,h;     
        virtual double Area(){return (d+c)*h/2.0;}
};
CShape *pShapes[100]; 
int main()
{
    int i;
    CRectangle *pr; CCircle *pc; CTriangle *pt;
    Square *ps;Trapezoid *ptt;
    for( i = 0;i < 5;++i ) {
        switch(i) {    
            case 0:
            pc  = new CCircle();
            cin >> pc->r;
            pShapes[i] = pc;
            break;
            case 1: 
            ps = new Square();
            cin >> ps->w;
            pShapes[i] = ps;
            break;
            case 2:
            pr = new CRectangle();
            cin >> pr->w >> pr->h;
            pShapes[i] = pr;
            break;
            case 3: 
            ptt  = new Trapezoid();
            cin >> ptt->d>> ptt->c>> ptt->h;
            pShapes[i] = ptt;
            break;
            case 4:
            pt = new CTriangle();
            cin >> pt->a >> pt->b;
            pShapes[i] = pt;
            break; 
        }
    }
    double count=0;
    for(i = 0;i <5;++i) 
    count+=pShapes[i]->Area();
    cout<<fixed<<setprecision(3)<<count;
    return 0;
}