Basic CPP Homework

C++第一次上机

5-1使用引用作为函数参数

#include<iostream>
using namespace std;
void exchange(int& x,int& y)
{
    int temp = x;
    x = y;
    y = temp;
}

int main(){
   int a, b;
    cin >> a >> b;
    exchange(a, b);
    cout << " exchange: " << a << " "<< b << endl;
    return 0;
}

The meaning of Class

填空,实现部分类的特征只能读取,部分类的特征可读可写,部分类的属性只能写入

```



## 5-3显式使用this指针

填写程序中的空白,完成指定的功能。

```cpp
#include<iostream>
using namespace std;
class R{
    int len,w;
    public:
    R(int len,int w);
    int getArea();
};
R::R(int len,int w){
    this->len=len;
    this->w=w;
}
int R::getArea(){
    return (this->len)*(this->w);
}
int main(){
    R r1(2,5),r2(3,6);
    cout<<"First Area is "<<r1.getArea()<<endl;
    cout<<"Second Area is "<<r2.getArea()<<endl;
    return 0;
}

5-4动态对象的创建

#include<bits/stdc++.h>
using namespace std;
class A{
    int i;
    public:
    A(int k=0){
        i=k;
    }
    void display(){
        cout<<"i="<<i<<endl;
    }
};
int main(){
    A* p=new A;//动态创建对象p
    p->display();
    delete p;//删除对象p
    p=new A(8);
    p->display();
    delete p;
    p=new A[3];//p指向对象数组
    A* q=p;
    for(int i=0;i<3;i++){
        q[i].display();//输出对象数组数据
    }
    delete[] p;//删除对象数组指针p
    return 0;
}

5-5静态数据成员

#include<iostream>
using namespace std;
class Point{
    double x,y;
    static int count;//定义静态变量
    public:
    Point(double a=0,double b=0):x(a),y(b){
        count++;
    }
    ~Point(){
        count--;
    }
    void show(){
        cout<<"the number of Point is "<<count<<endl;
    }
};
int Point::count=0;
int main(){
    Point p1;
    Point* p=new Point(1,2);
    p->show();
    delete p;
    p1.show();
    return 0;
}

5-6点类的定义和使用

已知平面上的一点由其横纵坐标来标识。本题要求按照已给代码和注释完成一个基本的“点”类的定义(坐标均取整型数值)。并通过主函数中的点类对象完成一些简单操作,分析程序运行结果,将答案写在对应的空格中。

#include <iostream>
using namespace std;

class Point{
    private://访问权限设置,私有权限
    int x;//横坐标
    int y;//纵坐标
    //访问权限设置,公有权限
    public:
    //以下为构造函数,用参数a,b分别为横纵坐标进行初始化
    Point(int a,int b){
        this->x=a;
        this->y=b;
    }

    //以下为拷贝构造函数,借用对象a_point完成初始化
    Point(const Point& a_point){
        x=a_point.x;
        y=a_point.y;
    }

    //以下为析构函数
    ~Point(){
        cout<<"Deconstructed Point";
        print();
    }

    //以下为输出点的信息的函数,要求在一行中输出点的坐标信息,形如:(横坐标,纵坐标)
    void print(){
        cout<<"x="<<this->x<<",y="<<this->y<<endl;
    }
};

int main(){
    Point b_point(0,0);
    b_point.print();
    int a,b;
    cin>>a>>b;//从标准输入流中提取数值给a,b
    Point c_point(a,b);
    c_point.print();
    return 0;//主函数的返回语句
}

5-7排队队吃果

幼稚园阿姨发糖,先到先得。请查询资料,使用队列(queue)容器模拟幼稚园小朋友Jack、Mary、Tom、Angela和Alex依次到达(入队)并依次出队领糖的过程。

#include <iostream>
#include<queue>
using namespace std;
int main(){
    queue<string> q;
    q.push("Jack");
    q.push("Mary");
    q.push("Tom");
    q.push("Angela");
    q.push("Alex");
    while (!q.empty()){
        string s = q.front();
        q.pop();
        cout << s<< " get candy." << endl;
    }
    return 0;
}

5-8 new/delete

#include<bits/stdc++.h>
// using namespace std;
int main(){
    int* pi=new int(10);
    //new 一个int对象,初始值为10
    std::cout<<"*pi="<<*pi<<std::endl;
    *pi=20;//通过指针改变变量的值
    std::cout<<"*pi = "<<*pi<<std::endl;
    delete pi;//释放int对象
    return 0;
}

6-1 平面矩形 - 《C++编程基础及应用》- 习题13-4

分数 20

作者 海洋饼干叔叔

单位 重庆大学

在一个平面内,由左上角(top left)顶点坐标结合右下角(bottom right)顶点坐标即可确定一个平面矩形。请设计Rect和Point类,使其可以被下述代码所利用,并产生期望的输出。

裁判测试程序样例:

//Project - Rect
#include <iostream>
#include <cmath>
using namespace std;

//定义Point类
//定义Rect类

int main() {
    auto rt = Rect(Point(1,6),Point(7,8));
    printf("Vertices of rectangle rt:\n");
    printf("(%d,%d)-----------------------(%d,%d)\n",
           rt.tl.x,rt.tl.y,rt.topRight().x,rt.topRight().y);

    printf("(%d,%d)-----------------------(%d,%d)\n",
           rt.bottomLeft().x,rt.bottomLeft().y,rt.br.x,rt.br.y);

    printf("Size information of rectangle rt:\n");
    printf("width - %d    height - %d\n",rt.width(),rt.height());
    printf("area - %d    diagonal legnth - %.2f",rt.area(),rt.diagonalLength());

    return 0;
}

输入样例:

输出样例:

Vertices of rectangle rt:
(1,6)-----------------------(7,6)
(1,8)-----------------------(7,8)
Size information of rectangle rt:
width - 6    height - 2
area - 12    diagonal legnth - 6.32

请注意:函数题只需要提交相关代码片段,不要提交完整程序。

  • Point topRight()生成并返回矩形右上角顶点坐标;
  • Point bottomLeft()生成并返回矩形左下角顶点的坐标;
  • 属性Point tl表示左上角顶点坐标, br表示右下角顶点坐标;
  • int width(), int height()分别计算并返回矩形的宽,高;
  • double diagonalLength()计算并返回矩形的对角线长度,使用勾股定理进行计算。

Code

240401

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

class Point{
    public:
    int x,y;
    Point(const int& _x,const int& _y):x(_x),y(_y){}
    ~Point(){}
};

class Rect{
    public:
    Point tl,br;
    Rect(const Point& _p1,const Point& _p2):tl(_p1),br(_p2){}
    ~Rect(){}
    Point topRight(){
        return Point(br.x,tl.y);
    }
    Point bottomLeft(){
        return Point(tl.x,br.y);
    }
    int width(){
        return abs(tl.x-br.x);
    }
    int height(){
        return abs(tl.y-br.y);
    }
    int area(){
        return this->width()*this->height();
    }
    double diagonalLength(){
        return sqrt(this->width()*this->width()+this->height()*this->height());
    }
};


int main(){
    auto rt=Rect(Point(1,6),Point(7,8));
    printf("Vertices of rectangle rt:\n");
    printf("(%d,%d)-----------------------(%d,%d)\n",
        rt.tl.x,rt.tl.y,rt.topRight().x,rt.topRight().y);

    printf("(%d,%d)-----------------------(%d,%d)\n",
        rt.bottomLeft().x,rt.bottomLeft().y,rt.br.x,rt.br.y);

    printf("Size information of rectangle rt:\n");
    printf("width - %d    height - %d\n",rt.width(),rt.height());
    printf("area - %d    diagonal legnth - %.2f",rt.area(),rt.diagonalLength());

    return 0;
}

6-2 类的定义(学生类Student)

分数 10

作者 刘骥

单位 重庆大学

本题要求定义一个学生类Student,数据成员包含姓名name和年龄age,类的声明见给出的代码,请给出类的完整实现,并通过测试程序。

类的声明:

class Student{
    private:
        string name;
        int age;
    public:
        Student(string name,int age);
        string getName() const;
        int getAge() const ;
        void setName(string name);
        void setAge(int age);
};

测试程序:

#include<iostream>
#include<string>
using namespace std;
class Student{
    private:
        string name;
        int age;
    public:
        Student(string name,int age);
        string getName() const;
        int getAge() const ;
        void setName(string name);
        void setAge(int age);
};

/* 请在这里填写答案 */

int main(){
    Student a("Zhang",20);
    cout<<"name="<<a.getName()<<endl;
    cout<<"age="<<a.getAge()<<endl;
    a.setName("Li");
    a.setAge(30);
    cout<<"name="<<a.getName()<<endl;
    cout<<"age="<<a.getAge()<<endl;
    return 0;
}

测试程序的输入:

测试程序的输出:

name=Zhang
age=20
name=Li
age=30

提示

下列代码为类实现的骨架代码

Student::Student(string name,int age){
    //代码
}
string Student::getName() const{
    //代码
}
int Student::getAge() const{
    //代码
}
void Student::setName(string name)
{
    //代码
}
void Student::setAge(int age)
{
    //代码
}

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

Code

240401

#include<iostream>
#include<string>
using namespace std;
class Student{
    private:
    string name;
    int age;
    public:
    Student(string name,int age);
    string getName() const;
    int getAge() const;
    void setName(string name);
    void setAge(int age);
};

Student::Student(string name,int age){
    this->name=name;
    this->age=age;
}
string Student::getName() const{
    return this->name;
}
int Student::getAge() const{
    return this->age;
}
void Student::setName(string name){
    this->name=name;
}
void Student::setAge(int age){
    this->age=age;
}

int main(){
    Student a("Zhang",20);
    cout<<"name="<<a.getName()<<endl;
    cout<<"age="<<a.getAge()<<endl;
    a.setName("Li");
    a.setAge(30);
    cout<<"name="<<a.getName()<<endl;
    cout<<"age="<<a.getAge()<<endl;
    return 0;
}

6-3 动态输入排序

分数 20

作者 乔

单位 湖南工程学院计算机与通信学院

本题要求实现一个函数input,能够输入n个整数。

裁判测试程序样例:

/* 请在这里填写答案 */
//实现input函数

void sort(int a[], int n){
    int i,j;
    for(i=0;i<n-1;i++){
        int min = i;
        for(j=i+1;j<n;j++){
            if(a[min]>a[j]) min = j; 
        }
        int t = a[i]; a[i] = a[min]; a[min] = t;
    }
}

int main(){
    int *a;
    int n; 
    cin>>n;                //输入数据的数量 
    input(a,n);            //输入n个整数 
    sort(a,n);            //将数组a按从小到大排序
    for(int i=0;i<n;i++) 
        cout<<a[i]<<" "; //按顺序输出
    
    if(a!=NULL)
        delete []a; 
    return 0;    
}

输入样例:

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

5
10 9 8 7 6

输出样例:

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

6 7 8 9 10 

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

Code

240401

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

void input(int*& a,int& n){
    a=new int[n];
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
}

void sort(int a[],int n){
    int i,j;
    for(i=0;i<n-1;i++){
        int min=i;
        for(j=i+1;j<n;j++){
            if(a[min]>a[j]) min=j;
        }
        int t=a[i]; a[i]=a[min]; a[min]=t;
    }
}

int main(){
    int* a;
    int n;
    cin>>n; //输入数据的数量 
    input(a,n); //输入n个整数 
    sort(a,n); //将数组a按从小到大排序
    for(int i=0;i<n;i++)
        cout<<a[i]<<" "; //按顺序输出
    if(a!=NULL)
        delete[]a;
    return 0;
}

6-4 客户机类

分数 10

作者 杨军

单位 四川师范大学

实现客户机(Client)类。定义字符型静态数据成员ServerName,保存其服务器名称;整型静态数据成员ClientNum,记录已定义的客户机数量;定义静态函数ChangeServerName()改变服务器名称。完成程序,使得提供的测试程序可以运行并得到要求的结果。

函数接口定义:

根据要求实现类代码

裁判测试程序样例:

/*在这里完成类代码*/
在这里给出函数被调用进行测试的例子。例如:
int main(){
    Client::show();
    Client c1;
    Client::show();
    Client::changeServerName('B');
    Client::show();
}

输入样例:

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

输出样例:

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

server name:A
num of clients:0
server name:A
num of clients:1
server name:B
num of clients:1

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

Code

240401

这题纯纯sb,裁判机居然不自带头文件。

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

class Client{
public:
    static int ClientNum;
    static char ServerName;
    Client(){
        ClientNum++;
    }
    static void show(){
        cout<<"server name:"<<ServerName<<"\n";
        cout<<"num of clients:"<<ClientNum<<"\n";
    }
    static void changeServerName(char ch){
        ServerName=ch;
    }
};

int Client::ClientNum=0;
char Client::ServerName='A';

6-5 日复一日 - 《C++编程基础及应用》- 习题13-2

分数 20

作者 海洋饼干叔叔

单位 重庆大学

设计符合下述要求的日期类(Date),使得下述代码可以正常运行。

  1. 拥有数据成员year、month和day,分别存储年、月、日;
  2. 构造函数接受年、月、日参数并初始化全部数据成员;
  3. 公有成员函数toText()返回一个string对象,该字符串为该日期对象的文字表达,比如“2022-5-20”;
  4. 公有成员函数nextDay()返回一个Date对象,表示该日期的后一天;
  5. 公有成员函数prevDay()返回一个Date对象,表示该日期的前一天。

裁判测试程序样例:

#include <iostream>
#include <string>
#include <assert.h>
using namespace std;

//请在此处定义Date类

int main()
{
    int year=2000,month=1,day=1;
    cin >> year >> month >> day;
    Date d(year,month,day);
    cout << "Date: " << d.toText() << ", Next Day: " << d.nextDay().toText()
         << ", Prev Day: " << d.prevDay().toText();
    return 0;
}

输入样例:

2000 3 1

说明:依次是年-月-日。

输出样例:

Date: 2000-3-1, Next Day: 2000-3-2, Prev Day: 2000-2-29

提示:需要注意闰年,闰年2月有29天,平年28天。 闰年判定函数:

bool isLeapYear(int year){
    //四年一闰,百年不闰,四百年又闰
    if (year%400==0)
        return true;
    else if (year%100==0)
        return false;
    else  if (year%4==0)
        return true;
    else
        return false;
}

请注意:函数题只需要提交相关代码片段,不要提交完整程序。

Code

240401

class Date{
private:
    int y,m,d;
    bool isLeapYear(int year){
        if(year%4!=0) return false; 
        if(year%400==0) return true;
        if(year%100==0) return false;
        return true; 
    }
public:
    Date(const int& _y,const int& _m,const int& _d):y(_y),m(_m),d(_d){}
    string toText(){
        return to_string(this->y)+"-"+to_string(this->m)+"-"+to_string(this->d);
    }
    Date(const Date& other){
        this->y=other.y;
        this->m=other.m;
        this->d=other.d;
    }
    Date nextDay(){
        Date res(*this);
        res.d++;
        if(res.m==2){
            if(isLeapYear(res.y)){
                if(res.d>29){
                    res.d-=29;
                    res.m++;
                }
            }else{
                if(res.d>28){
                    res.d-=28;
                    res.m++;
                }
            }
        }else if(res.m==1 || res.m==3 || res.m==5 || res.m==7 || res.m==8 || res.m==10 || res.m==12){
            if(res.d>31){
                res.d-=31;
                res.m++;
            }
        }else{
            if(res.d>30){
                res.d-=30;
                res.m++;
            }
        }
        if(res.m>12){
            res.m-=12;
            res.y++;
        }
        return res;
    }
    Date prevDay(){
        Date res(*this);
        res.d--;
        if(res.d>0) return res;
        res.m--;
        if(res.m==0) return Date(this->y-1,12,31);
        if(res.m==2){
            if(isLeapYear(res.y)) res.d=29;
            else res.d=28;
            return res;
        }if(res.m==1 || res.m==3 || res.m==5 || res.m==7 || res.m==8 || res.m==10 || res.m==12){
            res.d=31;
        }else{
            res.d=30;
        }
        return res;
    }
};

6-6 凸N边形的面积 - 《C++编程基础及应用》- 习题13-5

分数 20

作者 海洋饼干叔叔

单位 重庆大学

请设计符合下述要求的Point及Polygon类,使得程序可以正常运行。

平面内的N边形可以用N个顶点坐标来表示。请设计Point类表示一个顶点。请设计Polygon类表示一个N边形(N≥3):

  1. 私有数据成员pts类型为Point*,用于指向多边形的N个动态顶点对象;
  2. 构造函数接受一个整数n作为参数,n为多边形边数/点数;构造函数中需要动态分配顶点对象数组pts;
  3. setVertice(int i, const Point& p)成员函数用于设置第i个顶点的坐标;
  4. getVertice(i)成员函数获取并返回多边形的第i个顶点;
  5. 在析构函数中释放动态顶点对象;
  6. 公有函数getArea()计算并返回该多边形的面积(假设多边形为凸多边形,计算方法参考练习11-5)。

练习11-5中关于凸六边形面积计算的描述: 如图所示,当六边形为凸六边形时,可以将其拆分成四个三角形,利用海伦-秦九韶公式分别计算三角形的面积并相加,即得凸六边形的面积。

image.png

裁判测试程序样例:

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

//请在此处定义Point类及Polygon类

int main()
{
    Polygon poly1(6);
    poly1.setVertice(0,Point(0,0));
    poly1.setVertice(1,Point(33.2,30));
    poly1.setVertice(2,Point(61.2,0));
    poly1.setVertice(3,Point(61,-29.1));
    poly1.setVertice(4,Point(20,-57.7));
    poly1.setVertice(5,Point(0,-33.2));
    printf("Vertex 3 of poly 1: (%.1f, %.1f)\n",poly1.getVertice(3).x,poly1.getVertice(3).y);
    printf("Area of polygon 1: %.1f\n",poly1.getArea());


    Polygon poly2(4);
    poly2.setVertice(0,Point(0,0));
    poly2.setVertice(1,Point(33.2,0.7));
    poly2.setVertice(2,Point(20.3,-22));
    poly2.setVertice(3,Point(5.1,-19.7));
    printf("Vertex 2 of poly 2: (%.1f, %.1f)\n",poly2.getVertice(2).x,poly2.getVertice(2).y);
    printf("Area of polygon 2: %.1f\n",poly2.getArea());
    return 0;
}

输入样例:

输出样例:

Vertex 3 of poly 1: (61.0, -29.1)
Area of polygon 1: 3609.3
Vertex 2 of poly 2: (20.3, -22.0)
Area of polygon 2: 516.2

请注意:函数题只需要提交相关代码片段,不要提交完整程序。

Code

240401

class Point{
public:
    double x,y;
    Point():x(0.0),y(0.0){}
    Point(const double& _x,const double& _y):x(_x),y(_y){}
    Point operator-(const Point& other) const{
        return Point(this->x-other.x,this->y-other.y);
    }
};

class Polygon{
private:
    Point* p;
    int size;
    double CrossProduct(const Point& p1,const Point& p2,const Point& root){
        Point vec1=p1-root;
        Point vec2=p2-root;
        return vec1.x*vec2.y-vec2.x*vec1.y;
    }
public:
    Polygon(const int& _size):size(_size){
        p=new Point[size];
    }
    void setVertice(int n,const Point& point){
        p[n]=point;
    }
    Point getVertice(int n){
        return p[n];
    }
    double getArea(){
        double area=0;
        for(int i=2;i<size;i++){
            area+=CrossProduct(p[i],p[i-1],p[0]);
        }
        return area/2.0;
    }
};

CPP第二次上机

5-1 知识点2:普通构造函数及初始化

  • 对象的初始化和清理也是两个非常重要的安全问题
  • 一个对象或者变量没有初始状态,对其使用后果是未知
  • 同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题
  • c++利用了构造函数析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。

构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

构造函数:类名(输入参数){函数体}

  1. 构造函数,没有返回值也不写void
  2. 函数名称与类名相同
  3. 构造函数可以有参数,因此可以发生重载
  4. 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次
  5. 构造函数可以使用“:”进行初始化

成员变量通过构造函数初始化

  • 在实现构造函数时,还可以通过“:”运算符,在构造函数后面初始化成员变量,这种方式称为列表初始化,其格式如下所示: 类名(输入参数列表): 成员变量1(输入参数1), 成员变量的2(输入参数2),…, 成员变量n(输入参数n) { 函数体 }

构造函数的调用顺序

  1. 类的成员变量也可以是属于别的类的对象
  2. 当创建对象a中含有属于别的类对象b时,先执行成员对象b的构造函数,再执行a的构造函数

例:

补全下面两个类,一个Birth,一个Student,后者的成员变量中含有前者的对象

#include<iostream>
using namespace std;
class Birth{
    public:
    Birth(int y,int m,int d):_year(y),_month(m),_day(d){
        cout<<"Birth类构造函数"<<endl;
    }
    void show(){ cout<<_year<<"-"<<_month<<"-"<<_day<<endl; }
    private:
    int _year;
    int _month;
    int _day;
};
class Student{
    public:
    Student(string name,int id,int y,int m,int d):birth(y,m,d){
        cout<<"Student类构造函数"<<endl;
        _name=name;
        _id=id;
    }
    void show(){
        cout<<_name<<_id<<endl;
        birth.show();
    }
    private:
    string _name;
    int _id;
    Birth birth;
};
int main(){
    Student stu("物联",10002,2022,9,1);
    stu.show();
    return 0;//最后输出结果中,先输出“Birth类构造函数”,再输出“Student类构造函数”
}

5-2 知识点3:拷贝构造函数及构造函数的重载

拷贝构造函数:构造函数名称(const 类名 &对象名) { 函数体 }

  1. 拷贝构造函数是一种特殊的构造函数,它具有构造函数的所有特性,并且使用本类对象的引用作为形参,其作用是使用一个已经存在的对象初始化该类的另一个对象。
  2. 在定义拷贝构造函数时,为了使引用的对象不被修改,通常使用const修饰引用的对象。

构造函数重载:类名(不同的输入参数){函数体}

  1. 当定义具有默认参数的重载构造函数时,要防止调用的二义性。

例:

补充Birth类与Student类的拷贝构造函数,并对Student类的构造函数重载

#include<iostream>
using namespace std;
class Birth{
    public:
    Birth(int year,int month,int day):_year(year),_month(month),_day(day){
        cout<<"Birth类构造函数"<<endl;
    }
    Birth(const Birth& other):_year(other._year),_month(other._month),_day(other._day){//拷贝构造函数 
        cout<<"Birth类拷贝构造函数"<<endl;
    }
    void show(){ cout<<_year<<"-"<<_month<<"-"<<_day<<endl; }
    private:
    int _year;
    int _month;
    int _day;
};
class Student{
    public:
    Student(string name,int id,int year,int month,int day):birth(year,month,day){
        cout<<"Student类构造函数"<<endl;
        _name=name;
        _id=id;
    }
    //重载构造函数,不需要输入生日,默认生日1990-1-1 
    Student(string name,int id):birth(Birth(1990,1,1)){
        cout<<"Student类重载构造函数"<<endl;
        _name=name;
        _id=id;
    }
    //拷贝构造函数,注意这里的birth对象初始化,需要调用Birth类的拷贝构造函数
    Student(const Student& other):birth(other.birth){
        cout<<"Student类拷贝构造函数"<<endl;
        _name=other._name;
        _id=other._id;
    }
    void show(){
        cout<<_name<<_id<<endl;
        birth.show();
    }
    private:
    string _name;
    int _id;
    Birth birth;
};
int main(){
    Student stu("物联22",10002,2000,1,1);
    Student stu2("物联222",10001);
    Student stu3(stu);
    return 0;
}

5-3 知识点4:析构函数

析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。


析构函数语法: ~类名(){}

  1. 析构函数,没有返回值也不写void
  2. 函数名称与类名相同,在名称前加上符号 ~
  3. 析构函数不可以有参数,因此不可以发生重载
  4. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
  5. 析构函数没有返回值,不能在析构函数名称前添加任何返回值类型。在析构函数内部,也不能通过return返回任何值。

析构函数的调用顺序

  • 析构函数的调用顺序与构造函数的调用顺序是相反的。在构造对象和析构对象时,C++遵循的原则是:先构造的后析构,后构造的先析构。

什么时候调用析构函数

  1. 在一个函数中定义了一个对象,当函数调用结束时,对象应当被释放,对象释放之前,编译器会调用析构函数释放资源。
  2. static修饰的对象和全局对象,只有在程序结束时才会调用析构函数。
  3. new运算符创建的对象,在调用delete释放对象时,编译器会调用析构函数释放资源。

例:为Student类与Birth类加入析构函数,并观察Birth类与Student类析构函数调用顺序

#include<iostream>
using namespace std;
class Birth{
    public:
    Birth(int year,int month,int day):_year(year),_month(month),_day(day){
        //cout<<"Birth类构造函数"<<endl; 
    }
    Birth(const Birth& another):_year(another._year),_month(another._month),_day(another._day){
        //cout<<"Birth类拷贝构造函数"<<endl; 
    }
    ~Birth(){
        cout<<"Birth类析构函数"<<endl;
    }
    void show(){ cout<<_year<<"-"<<_month<<"-"<<_day<<endl; }
    private:
    int _year;     int _month;     int _day;
};
class Student{
    public:
    Student(string name,int id,int year,int month,int day):birth(year,month,day){
        //cout<<"Student类构造函数"<<endl;
        _name=name;
        _id=id;
    }
    Student(string name,int id):birth(1900,1,1){
        //cout<<"Student类重载构造函数"<<endl;
        _name=name;
        _id=id;
    }
    Student(const Student& another):birth(another.birth){
        //cout<<"Student类拷贝构造函数"<<endl;
        _name=another._name;
        _id=another._id;
    }
    ~Student(){
        cout<<"Student类析构函数"<<_id<<endl;
    }
    void show(){
        cout<<_name<<_id<<endl;
        birth.show();
    }
    private:
    string _name;    int _id;     Birth birth;
};
void f(){
    //若函数中定义了对象,则在调用结束后立即调用析构函数 
    Student stu3("物联223",10003);
    //static修饰的对象时,只有在程序结束时才会调用析构函数,位于main函数中定义的对象之后
    static Student stu4("物联224",10004);
}
int main(){
    Student stu("物联221",10001,2000,1,1);
    Student* stu2=new Student("物联222",10002);
    //new运算符创建的对象,在调用delete释放对象时立即调用析构函数    
    delete stu2;
    f();
    Student stu5("物联223",10005);
    return 0;
    //调用析构函数的顺序为(只填写id):,,,, 
}

5-4 知识点1:const修饰的成员变量与成员函数

分数 7

作者 郑远

单位 中国民用航空飞行学院

常成员变量:

  • 对于常成员变量,仅仅可以读取第一次初始化的数据,之后是不能修改的。
  • 常成员变量通常使用有参数构造函数进行初始化.
  • 语法 const 变量类型 变量名

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 类中定义的成员函数若与常成员函数名相同则构成重载,常成员函数只能由const修饰的对象进行访问。
  • 语法:返回值类型 函数名() const {}

常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数
  • 语法:const 类名 对象名(构造函数参数)

语法:

#include<iostream>
using namespace std;
class Person{
    public:
    Person():m_A(1){
        //const 修饰的成员变量,只有初始化时可以对其进行赋值,这里需要用初始化列表对m_A赋初值为1
        //const 修饰的成员变量需要用初始化参数表进行赋值,不能在函数体中进行赋值,这句话会报错 
        //m_A = 0;
        m_B=0;
    }
    //定义常成员函数ShowPerson,无返回值,无输入参数
    void ShowPerson() const{
        //const修饰成员函数,内部不能修改类成员,以下语句会报错 
        //this->m_B = 100;
        //但是可以调用
        cout<<this->m_B<<endl;
        cout<<"重载2"<<endl;
    }
    //定义非常成员函数ShowPerson,与上面函数构成重载,无返回值,无输入参数
    void ShowPerson(){
        cout<<"重载1"<<endl;
    }
    void MyFunc(){
        //const修饰的成员变量,除了初始化以外,在哪都不允许被修改,以下语句会报错 
        //mA = 10000;
        //但是可以调用
        cout<<this->m_A<<endl;
    }
    public:
    const int m_A;
    int m_B;
};
int main(){
    const Person person1;//常量对象  
    Person person2;//正常对象 

    //正常对象调用showperson,调用的是未经const修饰的重载函数showperson 
    person2.ShowPerson();
    person2.MyFunc();

    //常对象调用showperson,调用的是经过const修饰的重载函数showperson 
    person1.ShowPerson();
    //常对象不能调用普通成员函数,以下语句会报错 
    //person1.MyFunc();

    return 0;
}
//程序最后输出为:
//第一行:重载1
//第二行:1
//第三行:0
//第四行:重载2

5-5 知识点2:static修饰的成员变量与成员函数

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员 静态成员分为:

  • 静态成员变量 * 所有对象共享同一份数据 * 在编译阶段分配内存 * 静态成员变量定义语法 static 变量类型 变量名 * 类内声明,类外初始化,初始化语法为:变量类型 类名::变量名=初始化数(整体位于类定义的外面) * 可以通过对象或类进行调用:对象.静态成员变量名类名::静态成员变量名
  • 静态成员函数 * 所有对象共享同一个函数 * 静态成员函数只能访问静态成员变量 * 静态成员函数定义语法:static 函数名(){} * 可以通过对象或类进行调用:对象.静态函数名()类名::静态函数名()
#include<iostream>
using namespace std;
class Person{
public:
    static int m_A; //静态成员变量
    //静态成员函数func,没有输入
    static void func(){
        cout<<"func调用"<<endl;
        m_A=100;
        //m_B = 100; //静态成员函数不可以访问非静态成员变量,这句话会报错 
    }
private:
    static void func2()//静态成员函数也是有访问权限的
    {
        cout<<"func2调用"<<endl;
    }
    static int m_B; //静态成员变量也是有访问权限的
};
//静态成员变量初始化,私有对象可以在外面初始化但访问不了 
int Person::m_A=10;//初始化m_A
int Person::m_B=10;
int main(){
    //静态成员变量两种访问方式
    //1、通过对象
    Person p1;
    Person::m_A=100;//通过对象调用m_A
    cout<<"p1.m_A = "<<p1.m_A<<endl;

    Person p2;
    p2.m_A=200;
    cout<<"p1.m_A = "<<p1.m_A<<endl; //共享同一份数据
    cout<<"p2.m_A = "<<p2.m_A<<endl;

    //2、通过类名
    cout<<"m_A = " << Person::m_A << endl;//通过类名调用m_A
    //cout << "m_B = " << Person::m_B << endl; //私有权限访问不到

    //静态成员函数两种访问方式
    //1、通过对象
    Person p3;
    p3.func();//通过对象调用成员函数
    //2、通过类名
    Person::func();//通过类调用成员函数
    //Person::func2(); //私有权限访问不到    
    return 0;
}

知识点3:friend修饰的成员变量与成员函数

生活中你的家有客厅(Public),有你的卧室(Private);客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去。但是呢,你也可以允许你的好闺蜜好基友进去。

在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术;友元的目的就是让一个函数或者类 访问另一个类中私有成员

友元的关键字为 friend 友元的三种实现

  • 类做友元
  • 成员函数做友元
  • 全局函数做友元
  1. friend修饰别的类
  • 友元类可以声明在类中任意位置。friend class 类名
  • 声明友元类之后,友元类中的所有成员函数都是该类的友元函数,能够访问该类的所有成员。
  1. friend修饰成员函数
  • 友元成员函数声明语法:friend 函数返回值类型 类名::函数名();
  • 注意定义的先后,建议在前面进行声明,后面进行函数的同一定义,防止出现问题。
  1. friend修饰类外定义的函数
  • 将类外部的普通函数作为类的友元函数,在类中使用friend关键字声明该普通函数就可以实现,友元函数可以在类中任意位置声明。
  • 普通函数作为友元函数的声明形式如下所示: friend 函数返回值类型 友元函数名(形参列表)

Code

#include<iostream>
using namespace std;
class Building;
class goodGay{
    public:
    goodGay();
    void visit();
    private:
    Building* building;
};
class goodGayGay{
    public:
    goodGayGay();
    void visit(); //只让visit函数作为Building的好朋友,可以发访问Building中私有内容
    void visit2();
    private:
    Building* building;
};
class Building{
    //1.告诉编译器 goodGay类是Building类的好朋友,可以访问到Building类中私有内容
    friend goodGay;
    //2.告诉编译器  goodGayGay类中的visit成员函数 是Building好朋友,可以访问私有内容
    friend void goodGayGay::visit();
    //3.告诉编译器 printt全局函数 是 Building类的好朋友,可以访问类中的私有内容
    friend void printt(Building* building);

public:
    Building(){
        this->m_SittingRoom="客厅";
        this->m_BedRoom="卧室";
    }
    string m_SittingRoom; //客厅
private:
    string m_BedRoom; //卧室
};
//以下为具体定义函数 
goodGay::goodGay(){
    building=new Building;
}
void goodGay::visit(){
    cout<<"第一个好基友正在访问"<<building->m_SittingRoom<<endl;
    cout<<"第一个好基友正在访问"<<building->m_BedRoom<<endl;
}
goodGayGay::goodGayGay(){
    building=new Building;
}
void goodGayGay::visit(){
    cout<<"第二个好基友正在访问"<<building->m_SittingRoom<<endl;
    cout<<"第二个好基友正在访问"<<building->m_BedRoom<<endl;
}
void goodGayGay::visit2(){
    cout<<"第二个好基友正在第二次访问"<<building->m_SittingRoom<<endl;
    //cout << "第二个好基友正在第二次访问" << building->m_BedRoom << endl;
}
void printt(Building* building){
    cout<<"第三个好基友正在访问: "<<building->m_SittingRoom<<endl;
    cout<<"第三个好基友正在访问: "<<building->m_BedRoom<<endl;
}
void test01(){
    goodGay gg;
    gg.visit();
}
void test02(){
    goodGayGay gg;
    gg.visit();
}
void test03(){
    Building b;
    printt(&b);
}

int main(){
    test01();//friend修饰别的类
    test02();//friend修饰成员函数
    test03();//friend修饰类外定义的函数
    return 0;
}

6-1 猫和老鼠有多重

定义猫和老鼠:Cat与Mouse两个类,二者都有weight属性,定义二者的一个友元函数totalweight(),计算二者的重量和。

裁判测试程序样例:

#include <iostream>
using namespace std;

/* 请在这里填写答案 */

int main()
{
  int w1,w2;
  cin>>w1>>w2;
  Cat tom(w1);
  Mouse jerry(w2);
  cout<<totalWeight(tom,jerry)<<endl;
}

输入样例:

100 200

输出样例:

300

Code

240415

class Cat;
class Mouse;
int totalWeight(const Cat& w1,const Mouse& w2);

class Cat{
private:
    int weight;
public:
    Cat(int w):weight(w){}
    friend int totalWeight(const Cat& w1,const Mouse& w2);
};

class Mouse{
private:
    int weight;
public:
    Mouse(int w):weight(w){}
    friend int totalWeight(const Cat& w1,const Mouse& w2);
};

int totalWeight(const Cat& w1,const Mouse& w2){
    return w1.weight+w2.weight;
}

6-2 你好,拷贝构造函数

定义一个类Point

  • 构造函数传入xy的坐标值(整数),如果不传,默认都为0
  • 编写复制构造函数
  • display函数用于输出这个点的xy坐标,以空格分隔

裁判测试程序样例:

#include <iostream>
using namespace std;

// 答案写在这里

int main()
{
    int x, y;
    cin >> x >> y;
    Point p1(x, y);
    Point p2;
    Point p3(p1);
    p1.display();
    p2.display();
    p3.display();
    return 0;
}

输入样例:

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

3 4

输出样例:

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

3 4
0 0
3 4

Code

240415

class Point{
private:
    int x,y;
public:
    Point():x(0),y(0){}
    Point(int _x,int _y):x(_x),y(_y){}
    Point(const Point& another){
        this->x=another.x;
        this->y=another.y;
    }
    void display(){
        cout<<x<<" "<<y<<endl;
    }
};

6-3 复数类

  1. 已知一个名为Complex的复数类,这个类包含: (1)私有成员:实部、虚部,且均为int 型 (2)公有的带默认形参值的构造函数、复制构造函数 (3)公有成员函数Display,其作用为显示复数 要求: (1)实现满足上述属性和行为的Complex类定义; (2)设计函数AddComplex,函数AddComplex功能为实现两个复数相加,要求该函数的形参为复数类的常引用; (3)保证如下主函数能正确运行。

裁判测试程序样例:

/* 请在这里填写答案 */

int main(){
    int x,y;
    cin>>x>>y;
        Complex  c0(x,y);
        Complex  c1(c0);
        cout<<"c1 is: "; 
        c1.Display();
        cin>>x>>y; 
        Complex c2(x,y);
        cout<<"c2 is: "; 
        c2.Display();
        Complex c3;
        c3 = AddComplex(c1,c2); 
        cout<<"c3 is: "; 
        c3.Display();    
        return 0;
}

输入样例:

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

2 -3 
3 4

输出样例:

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

c1 is: 2-3i
c2 is: 3+4i
c3 is: 5+1i

Code

240415

#include<iostream>
using namespace std;

class Complex;
Complex AddComplex(const Complex& c1,const Complex& c2);

class Complex{
private:
    int x,y;
public:
    Complex():x(0),y(0){}
    Complex(int _x,int _y):x(_x),y(_y){}
    void Display(){
        cout<<x;
        if(y>0) cout<<"+"<<y<<"i";
        else if(y<0) cout<<y<<"i";
        cout<<"\n";
    }
    friend Complex AddComplex(const Complex& c1,const Complex& c2);
};

Complex AddComplex(const Complex& c1,const Complex& c2){
    return Complex(c1.x+c2.x,c1.y+c2.y);
}

6-4 实现数组类(C++ 拷贝构造函数、拷贝函数)

裁判测试程序样例中展示的是一段实现“数组类”的代码,其中缺失了部分代码,请补充完整,以保证测试程序正常运行。

函数接口定义:

提示:要想程序正确运行,至少需要补充以下函数(可能还需要补充其他函数):
1. 带参构造函数
2. 拷贝构造函数
3. 拷贝函数(赋值运算符重载)

裁判测试程序样例:

#include <iostream>
using namespace std;
class ArrayIndexOutOfBoundsException{  // 异常类
public:
    int index;
    ArrayIndexOutOfBoundsException(int k){
        index = k;
    }
};
class Array{
private:
    int *data;
    int size;
    static const int dSize = 10;   // 数组默认大小
public:
    Array( ){  // 无参构造
        size = dSize;
        data = new int[size]( );
    }
        
/** 你提交的代码将被嵌在这里(替换本行内容) **/        
        
    int& operator [] (int k){     // 运算符 [ ] 重载,以方便数组的使用
        if(k<0 || k>=size) throw ArrayIndexOutOfBoundsException(k);
        return data[k];
    }
    friend ostream& operator << (ostream& o, const Array& a);   // 运算符 << 重载,以方便输出
};
ostream& operator << (ostream& o, const Array& a){
    o << '[' ;
    for(int i=0; i<a.size-1; i++)
        o << a.data[i] << ',' ;
    o << a.data[a.size-1] << ']';
    return o;
}
// 注意:实际测试程序中,在此处之前的代码与样例中相同
// 注意:实际测试程序中,在此处之后的代码(即main函数)可能与样例中不同
int main(){
    int n, k;
    cin >> n >> k;
    Array a(n);  // 构造数组,大小为 n
    for(int i=0; i<n; i++) a[i] = i;
    Array b = a;  // 拷贝构造数组
    b[n/2] = k;
    cout << a << endl;
    cout << b << endl;
    Array c;  // 构造数组,默认大小
    c = a; // 拷贝数组
    c[n/2] = k;
    cout << a << endl;
    cout << c << endl;
    a = a;
    a[n/2] = 2223;
    cout << a << endl;
    return 0;
}

输入样例:

15 666

输出样例:

[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
[0,1,2,3,4,5,6,666,8,9,10,11,12,13,14]
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
[0,1,2,3,4,5,6,666,8,9,10,11,12,13,14]
[0,1,2,3,4,5,6,2223,8,9,10,11,12,13,14]

Code

240415

Array(int n): size(n){
    data=new int[size]();
}

Array(const Array& other){
    size=other.size;
    data=new int[size]();
    // stdcpy(data,other.data,sizeof(int)*size);
    copy(other.data,other.data+size,data);
}

~Array(){
    delete[] data;
}

Array& operator=(const Array& other){
    if(this!=&other){  // 防止自赋值
        // 释放旧资源
        delete[] data;

        // 深拷贝新资源
        size=other.size;
        data=new int[size]();
        for(int i=0; i<size; ++i){
            data[i]=other.data[i];
        }
    }
    return *this;
}

7-1 队列操作

请实现一个MyQueue类,实现出队,入队,求队列长度

实现入队函数 void push(int x); 实现出队函数 int pop(); 实现求队列长度函数 int size();

输入格式:

每个输入包含1个测试用例。每个测试用例第一行给出一个正整数 n (n <= 10^6) ,接下去n行每行一个数字,表示一种操作: 1 x : 表示从队尾插入x,0<=x<=2^31-1。 2 : 表示队首元素出队。 3 : 表示求队列长度。

输出格式:

对于操作2,若队列为空,则输出 “Invalid”,否则请输出队首元素。 对于操作3,请输出队列长度。 每个输出项最后换行。

输入样例:

5
3
2
1 100
3
2

输出样例:

0
Invalid
1
100

Code

240415

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

int main(){
    int op,val;
    queue<int> q;
    while(cin>>op){
        if(op==1){
            cin>>val;
            q.push(val);
        }else if(op==2){
            if(q.empty()) cout<<"Invalid\n";
            else cout<<q.front()<<"\n",q.pop();
        }else if(op==3){
            cout<<q.size()<<"\n";
        }
    }
    return 0;
}

7-2 完成队列类的拷贝控制函数

在队列类中添加拷贝构造函数、移动构造函数、移动赋值函数、重载赋值运算符=。并在主函数中测试:

调用拷贝构造函数,用已定义的一个队列类对象q构造新定义的对象q1。

调用赋值运算符,将一个已定义的队列类对象q赋值给另一个对象q2。

移除q的第一个元素。

输入格式:

输入一组整数到队列对象中,以ctrl+Z+enter结束输入。

输出格式:

q中的元素;

q1中的元素;

q2中的元素;

输入样例:

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

3 9 1

输出样例:

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

9 1
3 9 1
3 9 1

Code

240415

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


int main(){
    vector<int> v;
    int t;
    while(cin>>t) v.emplace_back(t);
    for(int i=1;i<v.size();i++){
        if(i!=1) cout<<" ";
        cout<<v[i];
    }
    cout<<"\n";
    for(int i=0;i<v.size();i++){
        if(i) cout<<" ";
        cout<<v[i];
    }
    cout<<"\n";
    for(int i=0;i<v.size();i++){
        if(i) cout<<" ";
        cout<<v[i];
    }
    cout<<"\n";
    return 0;
}

7-3(选做) 无符号大数类

设计并实现一个具有构造、+、-、*、/、%、>、<、>=、<=、!=、==、<<等功能的无符号大数类。(为便于运算,无符号大数内部存放连续十进制位时采用低位在前、高位在后的方式,去除高位多余的0。无符号大数类应支持复制和赋值)

输入格式:

输入两个无符号大数A、B。

输出格式:

输出A+B=结果。

输入样例:

例如:

1234567890987654321333888999666
147655765659657669789687967867

输出样例:

输出结果:

1234567890987654321333888999666+147655765659657669789687967867=1382223656647311991123576967533

Code

240415

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

int main(){
    string a,b,res="";
    cin>>a>>b;
    while(a.length()>1 && a[0]=='0') a.erase(0);
    while(b.length()>1 && b[0]=='0') b.erase(0);
    int na=a.length(),nb=b.length();
    int pushup=0;
    int cur_a=na-1,cur_b=nb-1;
    while(cur_a>=0 && cur_b>=0){
        // cout<<"a["<<cur_a<<"]="<<a[cur_a]<<",b["<<
        int t=a[cur_a]-'0'+b[cur_b]-'0'+pushup;
        res=(char)(t%10+'0')+res;
        pushup=t/10;
        cur_a--;
        cur_b--;
    }
    while(cur_a>=0){
        int t=a[cur_a]-'0'+pushup;
        res=(char)(t%10+'0')+res;
        pushup=t/10;
        cur_a--;
    }
    while(cur_b>=0){
        int t=b[cur_b]-'0'+pushup;
        res=(char)(t%10+'0')+res;
        pushup=t/10;
        cur_b--;
    }
    if(pushup>0){
        res=(char)pushup+res;
    }
    cout<<a<<"+"<<b<<"="<<res<<"\n";
    return 0;
}

C++课后作业-运算符重载-继承

运算符重载

圆类定义如下,重载输入、输出运算符为友元函数,重载算术减法运算符为成员函数,参考给出代码进行填空。

#include<bits/stdc++.h>
using namespace std;
class Circle{
private:
    double rad;
    double area;
    friend istream& operator>>(istream& in,Circle& cl);       //重载>>为Circle类的友元函数
    friend ostream& operator<<(ostream& out,Circle& cl);        //重载<<为Circle类的友元函数
public:
    Circle(double r=0){
        rad=r;
        area=3.14*r*r;
    }
    double operator- (Circle& cl)//重载减号
    {
        return this->area-cl.area;//返回两个圆的面积差
    }
};
istream& operator>>(istream& in,Circle& cl){
    in>>cl.rad;   //从输入流中提取数据给圆的半径
    cl.area=3.14*cl.rad*cl.rad;
    return in;
}
ostream& operator<<(ostream& out,Circle& cl){
    out<<"rad="<<cl.rad<<" area="<<cl.area;    //输出圆的半径和面积,形如:rad=10 area=314
    return out;
}

int main(){
    Circle c1,c2;
    cin>>c1>>c2;
    cout<<c1<<endl;
    cout<<c2<<endl;
    cout<<c2-c1<<endl;
    return 0;
}

复数的加法及输出

下述程序从控制台读取一个复数b的实部和虚部,然后将这个复数与复数a及实数3.2相加,得到复数c并输出。请参考注释将程序补充完整。

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

class Complex{
    double dReal;
    double dImage;
    public:
    //构造函数
    Complex():dReal(0),dImage(0){};
    Complex(int a,int b):dReal(a),dImage(b){};

    //operator+操作符函数
    Complex operator+ (Complex& other){
        return Complex(this->dReal+other.dReal,this->dImage+other.dImage);
    }
    Complex operator+ (int _int){
        return Complex(this->dReal+_int,this->dImage);
    }
    Complex operator+ (double _double){
        return Complex(this->dReal+_double,this->dImage);
    }

    //友元函数声明以帮助operator<<()函数访问Complex类的私有成员
    friend ostream& operator<< (ostream& o,const Complex& c);
};

ostream& operator<<(ostream& o,const Complex& c){
    o<<fixed<<setprecision(1)<<c.dReal<<" + "<<c.dImage<<"i";
    return o;
}

int main(){
    double dReal,dImage;
    cin>>dReal>>dImage;

    Complex a(1,1);
    Complex b(dReal,dImage);
    Complex c=a+b+3.2;
    cout<<c<<endl;
    return 0;
}

5-3 多层派生时的构造函数

根据所定义的基类,完成派生类的定义。

#include <iostream>
#include<string>
using namespace std;
class Student{
    public:
    Student(int n,string nam){
        num=n;
        name=nam;
    }
    void display(){
        cout<<"num:"<<num<<endl;
        cout<<"name:"<<name<<endl;
    }
    protected:
    int num;
    string name;
};

class Student1: public Student{
    public:

    Student1(int n,string nam,int a):Student(n,nam){ age=a; }
    void show(){
        display();
        cout<<"age: "<<age<<endl;
    }
    private:
    int age;
};

class Student2:public Student1{
    public:

    Student2(int n,string nam,int a,int s):Student1(n,nam,a){ score=s; }
    void show_all(){
        show();
        cout<<"score:"<<score<<endl;
    }
    private:
    int score;
};

int main(){
    Student2 stud(10010,"Li",17,89);
    stud.show_all();
    return 0;
}

6-1 Point类的运算

定义Point类,有坐标x,y两个私有成员变量;对Point类重载“+”(相加)、“-”(相减)和“==”(相等)运算符,实现对坐标的改变,要求用友元函数和成员函数两种方法实现。对Point类重载<<运算符,以使得代码 Point p; cout<<p<<endl;可以输出该点对象的坐标。

函数接口定义:

实现Point类。

裁判测试程序样例:

/* 请在这里填写答案 */



int main(int argc, char const *argv[])
{
    Point p1(2,3);
    cout<<p1<<endl;
    Point p2(4,5);
    cout<<p2<<endl;
    Point p3 = p1+p2;    
    cout<<p3<<endl;
    p3 = p2-p1;
    cout<<p3<<endl;
    p1 += p2;
    cout<<p1<<endl;
    cout<<(p1==p2)<<endl;
    return 0;
}

输入样例:

输出样例:

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

2,3
4,5
6,8
2,2
6,8
0

Code

240514

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

class Point{
private:
    int x,y;
public:
    Point():x(0),y(0){};
    Point(int a,int b):x(a),y(b){};
    Point operator+ (const Point& other){
        return Point(this->x+other.x,this->y+other.y);
    }
    Point operator- (const Point& other){
        return Point(this->x-other.x,this->y-other.y);
    }
    void operator+= (const Point& other){
        this->x+=other.x;
        this->y+=other.y;
    }
    bool operator== (const Point& other){
        return this->x==other.x && this->y==other.y;
    }
    friend ostream& operator<< (ostream& o,const Point& point){
        o<<point.x<<","<<point.y;
        return o;
    }
};

int main(int argc,char const* argv[]){
    Point p1(2,3);
    cout<<p1<<endl;
    Point p2(4,5);
    cout<<p2<<endl;
    Point p3=p1+p2;
    cout<<p3<<endl;
    p3=p2-p1;
    cout<<p3<<endl;
    p1+=p2;
    cout<<p1<<endl;
    cout<<(p1==p2)<<endl;
    return 0;
}

6-2 派生类使用基类的成员函数

按要求完成下面的程序:

1、定义一个Animal类,成员包括:

(1)整数类型的私有数据成员m_nWeightBase,表示Animal的体重;

(2)整数类型的保护数据成员m_nAgeBase,表示Animal的年龄;

(3)公有函数成员set_weight,用指定形参初始化数据成员nWeightBase

(4)公有成员函数get_weight,返回数据成员nWeightBase的值;

(5)公有函数成员set_age,用指定形参初始化数据成员m_nAgeBase

2、定义一个Cat类,公有继承自Animal类,其成员包括:

(1)string类型的私有数据成员m_strName;

(2)带参数的构造函数,用指定形参对私有数据成员进行初始化;

(3)公有的成员函数print_age,功能是首先输出成员m_strName的值,然后输出“, age = ”,接着输出基类的数据成员m_nAgeBase的值。具体输出格式参见main函数和样例输出。

类和函数接口定义:

参见题目描述。

裁判测试程序样例:

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

/* 请在这里填写答案 */

int main()
{
    Cat cat("Persian");   //定义派生类对象cat
    cat.set_age(5);       //派生类对象调用从基类继承的公有成员函数
    cat.set_weight(6);    //派生类对象调用从基类继承的公有成员函数
    cat.print_age();      //派生类对象调用自己的公有函数
    cout << "cat weight = " << cat.get_weight() << endl;
    return 0;
}

输入样例:

本题无输入。

输出样例:

Persian, age = 5
cat weight = 6

Code

240514

class Animal{
private:
    int m_nWeightBase;
protected:
    int m_nAgeBase;
public:
    void set_weight(int n){
        this->m_nWeightBase=n;
    }
    int get_weight(){
        return m_nWeightBase;
    }
    void set_age(int n){
        this->m_nAgeBase=n;
    }
};

class Cat:public Animal{
private:
    string m_strName;
public:
    Cat(string s):m_strName(s){};
    void print_age(){
        cout<<this->m_strName<<", age = "<<this->m_nAgeBase<<endl;
    }
};

6-3 私有继承派生类使用基类的成员函数

按要求完成下面的程序:

1、定义一个Animal类,成员包括:

(1)整数类型的私有数据成员m_nWeightBase,表示Animal的体重;

(2)整数类型的保护数据成员m_nAgeBase,表示Animal的年龄;

(3)公有函数成员set_weight,用指定形参初始化数据成员m_nWeightBase

(4)公有成员函数get_weight,返回数据成员m_nWeightBase的值;

(5)公有函数成员set_age,用指定形参初始化数据成员m_nAgeBase

2、定义一个Cat类,私有继承自Animal类,其成员包括:

(1)string类型的私有数据成员m_strName;

(2)带参数的构造函数,用指定形参对私有数据成员进行初始化;

(3)公有的成员函数set_print_age,功能是首先调用基类的成员函数set_age设置数据成员m_nAgeBase的值为5,接着输出成员m_strName的值,然后输出“, age = ”,最后输出基类的数据成员m_nAgeBase的值。具体输出格式参见main函数和样例输出。

(4)公有的成员函数set_print_weight,功能是首先调用基类的成员函数set_weight设置数据成员nWeightBase的值为6,接着输出成员m_strName的值,然后输出“, weight = ”,最后调用基类的成员函数get_weight输出基类的数据成员m_nAgeBase的值。具体输出格式参见main函数和样例输出。

类和函数接口定义:

参见题目描述。

裁判测试程序样例:

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

/* 请在这里填写答案 */

int main()
{
    Cat cat("Persian");     //定义派生类对象cat
    cat.set_print_age();
    cat.set_print_weight(); //派生类对象调用自己的公有函数
    return 0;
}

输入样例:

本题无输入。

输出样例:

Persian, age = 5
Persian, weight = 6

Code

240514

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

class Animal{
private:
    int m_nWeightBase;
protected:
    int m_nAgeBase;
public:
    void set_weight(int n){
        this->m_nWeightBase=n;
    }
    int get_weight(){
        return m_nWeightBase;
    }
    void set_age(int n){
        this->m_nAgeBase=n;
    }
};

class Cat:private Animal{
private:
    string m_strName;
public:
    Cat(string s):m_strName(s){};
    void print_age(){
        cout<<this->m_strName<<", age = "<<this->m_nAgeBase<<endl;
    }
    void set_print_age(){
        this->m_nAgeBase=5;
        cout<<m_strName<<", age = "<<m_nAgeBase<<endl;
    }
    void set_print_weight(){
        this->set_weight(6);
        cout<<m_strName<<", weight = "<<this->get_weight()<<endl;
    }
};

int main(){
    Cat cat("Persian");     //定义派生类对象cat
    cat.set_print_age();
    cat.set_print_weight(); //派生类对象调用自己的公有函数
    return 0;
}

6-4 多重继承派生类构造函数

根据所给的基类Student和Teacher,定义Graduate类

类定义:

#include <iostream>
#include <string>
using namespace std;
class Teacher                          
 {public:                                 
   Teacher(string nam,int a,string t)      
    {name=nam;
     age=a;
     title=t;}
   void display()                         
     {cout<<"name:"<<name<<endl;
      cout<<"age"<<age<<endl;
      cout<<"title:"<<title<<endl;
     }
  protected:                          
    string name;
    int age;
    string title;                      
};

class Student                         
 {public:
   Student(string nam,char s,float sco)
     {name1=nam;
      sex=s;
      score=sco;}                        
   void display1()                      
    {cout<<"name:"<<name1<<endl;
     cout<<"sex:"<<sex<<endl;
     cout<<"score:"<<score<<endl;
    }
  protected:                             
   string name1;
   char sex;
   float score;                           
 };
 
 /* 请在这里填写答案 */

裁判测试程序样例:

int main( )
 {Graduate grad1("Wang-li",24,'f',"assistant",89.5,1234.5);
  grad1.show( );
  return 0;
}

输出样例:

name:Wang-li
age:24
sex:f
score:89.5
title:assistant
wages:1234.5

Code

240520

class Graduate:private Teacher,private Student{
public:
    Graduate(string name,int age,char s,string title,float score,float wages):Teacher(name,age,title),Student(name,s,score),wage(wages){};
    void show(){
        cout<<"name:"<<Teacher::name<<endl;
        cout<<"age:"<<Teacher::age<<endl;
        cout<<"sex:"<<Student::sex<<endl;
        cout<<"score:"<<Student::score<<endl;
        cout<<"title:"<<Teacher::title<<endl;

        // Graduate::Teacher::display();
        // Graduate::Student::display1();
        cout<<"wages:"<<wage<<endl;
    }
private:
    double wage;
};

6-5 鸭子也是鸟

按要求完成下面的程序:

1、定义一个Bird类,包含一个void类型的无参的speak方法,输出“Jiu-Jiu-Jiu”。

2、定义一个Duck类,公有继承自Bird类,其成员包括:

(1)私有string类型的成员name;

(2)带参数的构造函数,用指定形参对私有数据成员进行初始化;

(3)公有的成员函数printName,无形参,void类型,功能是输出成员name的值,具体输出格式参见main函数和样例输出。

裁判测试程序样例:

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

/* 请在这里填写答案 */

int main()
{
    Bird b;
    b.speak();
    Duck d("Donald"); //定义派生类对象
    d.printName();    //派生类对象使用本类成员函数
    d.speak();    //派生类对象使用基类成员函数
    return 0;
}

输入样例:

无输入

输出样例:

Jiu-Jiu-Jiu
Dird Name:Donald
Jiu-Jiu-Jiu

Code

240520

class Bird{
    public:
    void speak(){
        cout<<"Jiu-Jiu-Jiu"<<endl;
    }
};

class Duck:public Bird{
    public:
    Duck(string _name):name(_name){}
    void printName(){
        cout<<"Dird Name:"<<this->name<<endl;
    }
    private:
    string name;
};

6-6 运算符重载(复数类Complex)

本题要求定义一个复数类Complex,类的声明见给出的代码,请给出类的完整实现,并通过测试程序。类的声明包括如下内容:

  1. 数据成员,复数类的实部u和虚部v;
  2. 对复数类实部和虚部的访问函数;
  3. 构造函数;
  4. 加号、减号运算符重载(遵守复数的运算规则);
  5. 输入、输出运算符重载。

类的声明:

class Complex{
    private:
        double u;
        double v;
    public:
        Complex(double _u=0,double _v=0);
        Complex operator+(const Complex&b);
        Complex operator-(const Complex&b);
        double getU() const;
        double getV() const;
        friend ostream&operator<<(ostream&os,const Complex&c);
        friend istream&operator>>(istream&is,Complex&c);
};

测试程序:

class Complex{
    private:
        double u;
        double v;
    public:
        Complex(double _u=0,double _v=0);
        double getU() const;
        double getV() const;
        Complex operator+(const Complex&b);
        Complex operator-(const Complex&b);
        friend ostream&operator<<(ostream&os,const Complex&c);
        friend istream&operator>>(istream&is,Complex&c);
};
double Complex::getU() const
{
    return u;
}
double Complex::getV() const
{
    return v;
}
/* 请在这里填写答案 */

int main(){
    Complex a;
    cin>>a;
    cout<<"复数a为:"<<a<<endl;
    Complex b(3,4);
    Complex c=a+b;
    cout<<"复数c为:"<<c<<endl;
    Complex d=a-b;
    cout<<"复数d为:"<<d<<endl;
    return 0;
}

测试程序的输入:

10 5

测试程序的输出:

复数a为:u=10,v=5
复数c为:u=13,v=9
复数d为:u=7,v=1

提示

下列代码为类实现的骨架代码

Complex::Complex(double _u,double _v){
    //代码
}
Complex Complex::operator+(const Complex&b){
    //代码
}
Complex Complex::operator-(const Complex&b){
    //代码
}
ostream&operator<<(ostream&os,const Complex&c){
    //代码
}
istream&operator>>(istream&is,Complex&c){
    //代码
}

Code

240520

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

class Complex{
private:
    double u;
    double v;
public:
    Complex(double _u=0,double _v=0);
    double getU() const;
    double getV() const;
    Complex operator+(const Complex& b);
    Complex operator-(const Complex& b);
    friend ostream& operator<<(ostream& os,const Complex& c);
    friend istream& operator>>(istream& is,Complex& c);
};
double Complex::getU() const{
    return u;
}
double Complex::getV() const{
    return v;
}
Complex::Complex(double _u,double _v){
    this->u=_u;
    this->v=_v;
}
Complex Complex::operator+(const Complex&b){
    return Complex(this->u+b.u,this->v+b.v);
}
Complex Complex::operator-(const Complex&b){
    return Complex(this->u-b.u,this->v-b.v);
}
ostream&operator<<(ostream&os,const Complex&c){
    os<<"u="<<c.u<<",v="<<c.v;
    return os;
}
istream&operator>>(istream&is,Complex&c){
    is>>c.u>>c.v;
    return is;
}

int main(){
    Complex a;
    cin>>a;
    cout<<"复数a为:"<<a<<endl;
    Complex b(3,4);
    Complex c=a+b;
    cout<<"复数c为:"<<c<<endl;
    Complex d=a-b;
    cout<<"复数d为:"<<d<<endl;
    return 0;
}

6-7 N天以后 - 《C++编程基础及应用》- 习题17-2

改造练习13-1(日复一日)中的Date类并提交,使其可以与一个整数n相加或相减,得到该日期N天后/前的日期。

提示:

  1. 请参考题目(日复一日)中的Date类实现;
  2. 注意考虑闰月;
  3. 整数n的取值范围为[1,10000]。

裁判测试程序样例:

#include <iostream>
#include <string>
#include <assert.h>
using namespace std;

//在此处补充Date类的定义

int main()
{
    int y, m, d;
    cin >> y >> m >> d;
    Date d1(y,m,d);

    int n;
    cin >> n;

    cout << d1.toText() << " + " << n << " = " << (d1 + n).toText() << endl;
    cout << d1.toText() << " - " << n << " = " << (d1 - n).toText() << endl;
    return 0;
}

输入样例:

2022 8 31
2

说明:意为求2022年8月31日的后两天和前两天的日期。

输出样例:

2022-8-31 + 2 = 2022-9-2
2022-8-31 - 2 = 2022-8-29

请注意:函数题只需要提交相关代码片段,不要提交完整程序。

Code

240520

#include <iostream>
#include <string>
#include <assert.h>
using namespace std;

class Date {
private:
    int year;
    int month;
    int day;

    bool isLeapYear(int year) {
        if (year % 4 == 0) {
            if (year % 100 == 0) {
                if (year % 400 == 0)
                    return true;
                else
                    return false;
            }
            else
                return true;
        }
        else
            return false;
    }

    int daysInMonth(int month, int year) {
        switch (month) {
            case 1: case 3: case 5: case 7: case 8: case 10: case 12:
                return 31;
            case 4: case 6: case 9: case 11:
                return 30;
            case 2:
                return isLeapYear(year) ? 29 : 28;
            default:
                return 0;
        }
    }

public:
    Date(int y, int m, int d) : year(y), month(m), day(d) {}

    // string toText() const {
    //     return to_string(year) + "-" + (month < 10 ? "0" : "") + to_string(month) + "-" + (day < 10 ? "0" : "") + to_string(day);
    // }
    string toText() const {
        return to_string(year) + "-" + to_string(month) + "-" + to_string(day);
    }

    Date operator+(int n) const {
        Date newDate = *this;
        newDate.day += n;
        while (newDate.day > newDate.daysInMonth(newDate.month, newDate.year)) {
            newDate.day -= newDate.daysInMonth(newDate.month, newDate.year);
            newDate.month++;
            if (newDate.month > 12) {
                newDate.month = 1;
                newDate.year++;
            }
        }
        return newDate;
    }

    Date operator-(int n) const {
        Date newDate = *this;
        newDate.day -= n;
        while (newDate.day <= 0) {
            newDate.month--;
            if (newDate.month < 1) {
                newDate.month = 12;
                newDate.year--;
            }
            newDate.day += newDate.daysInMonth(newDate.month, newDate.year);
        }
        return newDate;
    }
};


int main(){
    int y,m,d;
    cin>>y>>m>>d;
    Date d1(y,m,d);

    int n;
    cin>>n;

    cout<<d1.toText()<<" + "<<n<<" = "<<(d1+n).toText()<<endl;
    cout<<d1.toText()<<" - "<<n<<" = "<<(d1-n).toText()<<endl;
    return 0;
}

6-8 复数排序 - 《C++编程基础及应用》- 习题17-4

设计符合下述要求的Complex复数类,使得下述程序可以正常运行:自定义>操作符函数,使得两个复数对象可以通过>操作符以“模”为基础进行大小比较。

要求:Complex的实部和虚部成员均使用double类型。

裁判测试程序样例:

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

//此处定义Complex类其及operator>()自定义操作符函数

int main()
{
    const int N = 10;
    Complex a[N];
    for (int i=0;i<N;i++)
        cin >> a[i].dReal >> a[i].dImage;

    //使用冒泡排序算法进行排序
    for (int i=N-1;i>0;i--)
        for (int j=0;j<i;j++){
            if (a[j]>a[j+1]){
                auto t = a[j];
                a[j] = a[j+1];
                a[j+1] = t;
            }
        }

    printf("Sorted array of complexes:\n");
    for (int i=0;i<N;i++)
        printf("(%.1f,%.1f),",a[i].dReal,a[i].dImage);

    return 0;
}

输入样例:

1.1  3.3
2.3  2.1
7.4  7.6
6.1  0.1
4.4  4.4
5.6 7.8
10.1 23.2
0.1  0.2
56.12 78.2
4.2 2.1

说明:依次输入10个复数的实部和虚部

输出样例:

Sorted array of complexes:
(0.1,0.2),(2.3,2.1),(1.1,3.3),(4.2,2.1),(6.1,0.1),(4.4,4.4),(5.6,7.8),(7.4,7.6),(10.1,23.2),(56.1,78.2),

请注意:函数题只需要提交相关代码片段,不要提交完整程序。

Code

240520

class Complex{
public:
    Complex():dReal(0.0),dImage(0.0){}
    Complex(double a,double b):dReal(a),dImage(b){}
    double dReal,dImage;
    bool operator>(const Complex& other){
        if(pow(this->dReal,2)+pow(this->dImage,2)>pow(other.dReal,2)+pow(other.dImage,2)) return true;
        return false;
    }
};

6-9 你好,同名成员/成员函数覆盖/成员函数重写

编写一个类MyPerson,继承自Person,并重写函数show,使得程序的输出符合预期。

裁判测试程序样例:

#include <iostream>

using namespace std;

class Person {
public:
    Person(int age, double height): m_age(age), m_height(height) {}
    void show() const {
        cout << "age: " << m_age << endl
             << "height: " << m_height << endl;
    }
protected:
    int m_age;
    double m_height;
};

// 答案填写在这里

int main()
{
    int age;
    double height;
    cin >> age >> height;
    MyPerson p(age, height);
    p.show();
    return 0;
}

输入样例:

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

18 1.7

输出样例:

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

Age: 18
Height: 1.7

Code

240520

C++第三次上机

2-1

对象之间的相互作用和通信是通过消息。( )不是消息的组成部分。

A. 接受消息的对象

B. 要执行的函数的名字

C. 要执行的函数的内部结构

D. 函数需要的参数


2-2

对定义重载函数的下列要求中,( )是错误的。

A. 要求参数的个数不同

B. 要求参数中至少有一个类型不同

C. 要求函数的返回值不同

D. 要求参数个数相同时,参数类型不同


2-3

下列函数中,( )不能重载。

A. 成员函数

B. 非成员函数

C. 析构函数

D. 构造函数


2-4

( )不是面向对象程序设计的主要特征。

A. 封装

B. 继承

C. 多态

D. 结构


2-5

在下面类声明中,关于生成对象不正确的是( )。

class point
{
public:
    int x;
    int y;
    point(int a,int b) {x=a;y=b;}
};

A. point p(10,2);

B. point *p=new point(1,2);

C. point *p=new point[2];

D. point *p[2]={new point(1,2), new point(3,4)};


2-6

执行以下的程序片段,将输出几个数字?

for(i=0;i<3;i++);
cout<<i;

A. 0

B. 1

C. 2

D. 3


2-7

下列对变量的引用中错误的是____。

A. int a; int &p = a;

B. char a; char &p = a;

C. int a; int &p; p=a;

D. float a; float &p = a;


2-8

多继承是指()。

A. 一个派生类同时继承多个基类

B. 多个派生类同时继承一个基类

C. 基类本身又是一个更高一级基类的派生类

D. 派生类本身又是更低一级派生类的基类


2-9

下列运算符中,不可以重载的是( )。

A. new

B. ++

C. .*

D. []


2-10

C++输出流的插入符是( )。

  1. //
  2. >>
  3. <<
  4. &

2-11

关于信息隐蔽

信息隐蔽是通过 ▁▁▁▁▁ 实现的。

A. 抽象性

B. 封装性

C. 继承性

D. 传递性


2-12

类与对象的关系

在面向对象的开发方法中,类与对象的关系是 ▁▁▁▁▁。

A. 抽象与具体

B. 具体与抽象

C. 整体与部分

D. 部分与整体


2-13

下面对派生类的描述中,错误的是( )

A. 一个派生类可以作为另外一个派生类的基类

B. 派生类至少有一个基类

C. 派生类的成员除了它自己的成员外,还包含了它的基类的成员

D. 派生类中继承的基类成员的访问权限到派生类中保持不变


2-14

下列关于派生类构造函数和析构函数的说法中,错误的是()

A. 派生类的构造函数会隐含调用基类的构造函数

B. 如果基类中有默认构造函数,派生类可以不定义构造函数

C. 在建立派生类对象时,先调用基类的构造函数,再调用派生类的构造函数

D. 在销毁派生类对象时,先调用基类的析构函数,再调用派生类的析构函数


5-1 填写程序中的空白,完成指定的功能。

#include<iostream>
using namespace std;
class R{
    int len,w;
public:
    R(int len,int w);
    int getArea();
};
R::R(int len,int w){
    this->len=len;
    this->w=w;
}
int R::getArea(){
    return (this->len)*(this->w);
}
int main(){
    R r1(2,5),r2(3,6);
    cout<<"First Area is "<<r1.getArea()<<endl;
    cout<<"Second Area is "<<r2.getArea()<<endl;
    return 0;
}

输出数据如下:

First Area is 10
Second Area is 18

5-2 包含子对象的派生类构造函数

根据所定义的基类,定义派生类,请填空完成程序的功能

#include <iostream>
#include <string>
using namespace std;
class Student                              //声明基类
{
public:                                  //公用部分
    Student(int n,string nam)              //基类构造函数
    {
        num=n;
        name=nam;
    }
    void display()                           //输出基类数据成员
    {
        cout<<"num:"<<num<<endl<<"name:"<<name<<endl;
    }
protected:                                //保护部分
    int num;
    string name;
};

class Student1: public Student              //用public继承方式声明派生类student
{
public:
    //派生类构造函数
    Student1(int a,string b,int c,string d,int e,string ad):Student(a,b),monitor(c,b){
        age=a;                                 //在此处只对派生类新增的数据成员初始化
        addr=ad;
    }
    void show(){
        cout<<"This student is:"<<endl;
        display();                               //输出num和name
        cout<<"age: "<<age<<endl;
        cout<<"address: "<<addr<<endl<<endl;
    }

    void show_monitor()                        //输出子对象的数据成员
    {
        cout<<endl<<"Class monitor is:"<<endl;
        monitor.display();                       //调用基类成员函数
    }
private:                                //派生类的私有数据
    Student monitor;                       //定义子对象(班长)
    int age;
    string addr;
};

int main(){
    Student1 stud1(10010,"Wang-li",10001,"Li-sun",19,"115 Beijing Road,Shanghai");
    stud1.show();                             //输出第一个学生的数据
    stud1.show_monitor();                       //输出子对象的数据
    return 0;
}

程序输出如下

This student is:
num:10010
name:Wang-li
age: 19
address: 115 Beijing Road,Shanghai


Class monitor is:
num:10001
name:Li-sun

5-3 多层派生时的构造函数

根据所定义的基类,完成派生类的定义。

#include <iostream>
#include<string>
using namespace std;
class Student{
public:
    Student(int n,string nam){
        num=n;
        name=nam;
    }
    void display(){
        cout<<"num:"<<num<<endl;
        cout<<"name:"<<name<<endl;
    }
protected:
    int num;
    string name;
};

class Student1: public Student{
public:
    Student1(int Stu_n,string Stu_nam,int a):Student(Stu_n,Stu_nam){
        age=a;
    }
    void show(){
        display();
        cout<<"age: "<<age<<endl;
    }
private:
    int age;
};

class Student2:public Student1{
public:
    Student2(int Stu_n,string Stu_nam,int Stu1_a,int s):Student1(Stu_n,Stu_nam,Stu1_a){
        score=s;
    }
    void show_all(){
        show();
        cout<<"score:"<<score<<endl;
    }
private:
    int score;
};

int main(){
    Student2 stud(10010,"Li",17,89);
    stud.show_all();
    return 0;
}

5-4 知识点1:函数重载

作用:函数名可以相同,提高复用性 函数重载满足条件:

  • 同一个作用域下
  • 函数名称相同
  • 函数参数类型不同 或者 个数不同 或者 顺序不同

注意: 函数的返回值不可以作为函数重载的条件


例: 设计一个函数重载的程序,实现以下功能

输入两个整数,输出它们的和。 输入两个浮点数,输出它们的和。 输入两个字符串,输出它们的连接结果。 输入一个字符和一个整数,输出该字符重复该整数次的结果。

#include<iostream>
using namespace std;

int add(int a,int b){
    return a+b;
}
float add(float a,float b){
    return a+b;
}
string add(string a,string b){
    return a+b;
}
string add(char c,int n){
    string res="";
    for(int i=0; i<n; i++){
        res+=c;
    }
    return res;
}
int main(){
    int a=3,b=5;
    float c=1.2,d=3.4;
    string e="hello",f="world";
    char g='*';
    int n=4;
    cout<<"a + b = "<<add(a,b)<<endl;
    cout<<"c + d = "<<add(c,d)<<endl;
    cout<<"e + f = "<<add(e,f)<<endl;
    cout<<"g * n = "<<add(g,n)<<endl;
    return 0;
}

5-4 知识点3:拷贝构造函数及构造函数的重载

拷贝构造函数:构造函数名称(const 类名 &对象名) { 函数体 }

  1. 拷贝构造函数是一种特殊的构造函数,它具有构造函数的所有特性,并且使用本类对象的引用作为形参,其作用是使用一个已经存在的对象初始化该类的另一个对象。
  2. 在定义拷贝构造函数时,为了使引用的对象不被修改,通常使用const修饰引用的对象。

构造函数重载:类名(不同的输入参数){函数体}

  1. 当定义具有默认参数的重载构造函数时,要防止调用的二义性。

例:

补充Birth类与Student类的拷贝构造函数,并对Student类的构造函数重载

#include<iostream>
using namespace std;
class Birth{
public:
    Birth(int year,int month,int day):_year(year),_month(month),_day(day){
        cout<<"Birth类构造函数"<<endl;
    }
    Birth(const Birth& other): _year(other._year),_month(other._month),_day(other._day){//拷贝构造函数 
        cout<<"Birth类拷贝构造函数"<<endl;
    }
    void show(){ cout<<_year<<"-"<<_month<<"-"<<_day<<endl; }
private:
    int _year;     int _month;     int _day;
};
class Student{
public:
    Student(string name,int id,int year,int month,int day):birth(year,month,day){
        cout<<"Student类构造函数"<<endl;
        _name=name;
        _id=id;
    }
    //重载构造函数,不需要输入生日,默认生日1990-1-1 
    Student(string name,int id):birth(1990,1,1){
        cout<<"Student类重载构造函数"<<endl;
        _name=name;
        _id=id;
    }
    //拷贝构造函数,注意这里的birth对象初始化,需要调用Birth类的拷贝构造函数
    Student(const Student& other):birth(other.birth){
        cout<<"Student类拷贝构造函数"<<endl;
        _name=other._name;
        _id=other._id;
    }
    void show(){
        cout<<_name<<_id<<endl;
        birth.show();
    }
private:
    string _name;    int _id;     Birth birth;
};
int main(){
    Student stu("物联22",10002,2000,1,1);
    Student stu2("物联222",10001);
    Student stu3(stu);
    return 0;
}

5-6 知识点1:const修饰的成员变量与成员函数

常成员变量:

  • 对于常成员变量,仅仅可以读取第一次初始化的数据,之后是不能修改的。
  • 常成员变量通常使用有参数构造函数进行初始化.
  • 语法 const 变量类型 变量名

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 类中定义的成员函数若与常成员函数名相同则构成重载,常成员函数只能由const修饰的对象进行访问。
  • 语法:返回值类型 函数名() const {}

常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数
  • 语法:const 类名 对象名(构造函数参数)

语法:

#include<iostream>
using namespace std;
class Person{
public:
    Person():m_A(1){//const 修饰的成员变量,只有初始化时可以对其进行赋值,这里需要用初始化列表对m_A赋初值为1
        //const 修饰的成员变量需要用初始化参数表进行赋值,不能在函数体中进行赋值,这句话会报错 
        //m_A = 0;
        m_B=0;

    }
    //定义常成员函数ShowPerson,无返回值,无输入参数
    void ShowPerson() const{
        //const修饰成员函数,内部不能修改类成员,以下语句会报错 
        //this->m_B = 100;
        //但是可以调用
        cout<<this->m_B<<endl;
        cout<<"重载2"<<endl;
    }
    //定义非常成员函数ShowPerson,与上面函数构成重载,无返回值,无输入参数
    void ShowPerson(){
        cout<<"重载1"<<endl;
    }
    void MyFunc(){
        //const修饰的成员变量,除了初始化以外,在哪都不允许被修改,以下语句会报错 
        //mA = 10000;
        //但是可以调用
        cout<<this->m_A<<endl;
    }
public:
    const int m_A;
    int m_B;
};
int main(){
    const Person person1;//常量对象  
    Person person2;//正常对象 

    //正常对象调用showperson,调用的是未经const修饰的重载函数showperson 
    person2.ShowPerson();
    person2.MyFunc();

    //常对象调用showperson,调用的是经过const修饰的重载函数showperson 
    person1.ShowPerson();
    //常对象不能调用普通成员函数,以下语句会报错 
    //person1.MyFunc();

    return 0;
}
//程序最后输出为:
//第一行:重载1
//第二行:1
//第三行:0
//第四行:重载2
#include<iostream>
using namespace std;

class Person {
public:
    Person(int a = 1) : m_A(a) { // 使用初始化列表对m_A进行初始化
        m_B = 0;
    }

    // 重载函数,一个const版本,一个非const版本
    void ShowPerson() const {
        cout << "const重载" << endl;
        cout << "m_B: " << m_B << endl;
    }

    void ShowPerson() {
        cout << "非const重载" << endl;
    }

    void MyFunc() {
        // const修饰的成员函数内不能修改类的非mutable成员变量
        //m_A = 10000; // 这里会导致编译错误
        cout << "m_A: " << m_A << endl;
    }

public:
    const int m_A;
    int m_B;
};

int main() {
    const Person person1; // 常量对象
    Person person2; // 非常量对象

    person2.ShowPerson(); // 调用非const版本的ShowPerson()
    person2.MyFunc(); // 输出m_A的值

    person1.ShowPerson(); // 调用const版本的ShowPerson()
    //person1.MyFunc(); // 常量对象不能调用非const成员函数,这行会导致编译错误

    return 0;
}

5-7 知识点2:static修饰的成员变量与成员函数

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员 静态成员分为:

  • 静态成员变量 * 所有对象共享同一份数据 * 在编译阶段分配内存 * 静态成员变量定义语法 static 变量类型 变量名 * 类内声明,类外初始化,初始化语法为:变量类型 类名::变量名=初始化数(整体位于类定义的外面) * 可以通过对象或类进行调用:对象.静态成员变量名类名::静态成员变量名
  • 静态成员函数 * 所有对象共享同一个函数 * 静态成员函数只能访问静态成员变量 * 静态成员函数定义语法:static 函数名(){} * 可以通过对象或类进行调用:对象.静态函数名()类名::静态函数名()
#include<iostream>
using namespace std;
class Person{
public:
    static int m_A; //静态成员变量
    //静态成员函数func,没有输入
    static void func(){
        cout<<"func调用"<<endl;
        m_A=100;
        //m_B = 100; //静态成员函数不可以访问非静态成员变量,这句话会报错 
    }
private:
    static void func2()//静态成员函数也是有访问权限的
    {
        cout<<"func2调用"<<endl;
    }
    static int m_B; //静态成员变量也是有访问权限的
};
//静态成员变量初始化,私有对象可以在外面初始化但访问不了 
int Person::m_A=10;//初始化m_A
int Person::m_B=10;
int main(){
    //静态成员变量两种访问方式
    //1、通过对象
    Person p1;
    p1.m_A=100;//通过对象调用m_A
    cout<<"p1.m_A = "<<p1.m_A<<endl;

    Person p2;
    p2.m_A=200;
    cout<<"p1.m_A = "<<p1.m_A<<endl; //共享同一份数据
    cout<<"p2.m_A = "<<p2.m_A<<endl;

    //2、通过类名
    cout<<"m_A = "<<Person::m_A<<endl;//通过类名调用m_A
    //cout << "m_B = " << Person::m_B << endl; //私有权限访问不到

    //静态成员函数两种访问方式
    //1、通过对象
    Person p3;
    p3.func();//通过对象调用成员函数
    //2、通过类名
    Person::func();//通过类调用成员函数
    //Person::func2(); //私有权限访问不到    

    return 0;
}

5-8 知识点3:friend修饰的成员变量与成员函数

生活中你的家有客厅(Public),有你的卧室(Private);客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去。但是呢,你也可以允许你的好闺蜜好基友进去。

在程序里,有些私有属性 也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术;友元的目的就是让一个函数或者类 访问另一个类中私有成员

友元的关键字为 friend 友元的三种实现

  • 类做友元
  • 成员函数做友元
  • 全局函数做友元
  1. friend修饰别的类
  • 友元类可以声明在类中任意位置。friend class 类名
  • 声明友元类之后,友元类中的所有成员函数都是该类的友元函数,能够访问该类的所有成员。
  1. friend修饰成员函数
  • 友元成员函数声明语法:friend 函数返回值类型 类名::函数名();
  • 注意定义的先后,建议在前面进行声明,后面进行函数的同一定义,防止出现问题。
  1. friend修饰类外定义的函数
  • 将类外部的普通函数作为类的友元函数,在类中使用friend关键字声明该普通函数就可以实现,友元函数可以在类中任意位置声明。
  • 普通函数作为友元函数的声明形式如下所示: friend 函数返回值类型 友元函数名(形参列表)
#include<iostream>
using namespace std;
class Building;
class goodGay{
    public:
    goodGay();
    void visit();
    private:
    Building* building;
};
class goodGayGay{
    public:
    goodGayGay();
    void visit(); //只让visit函数作为Building的好朋友,可以发访问Building中私有内容
    void visit2();
    private:
    Building* building;
};
class Building{
    //1.告诉编译器 goodGay类是Building类的好朋友,可以访问到Building类中私有内容
    friend goodGay;
    //2.告诉编译器  goodGayGay类中的visit成员函数 是Building好朋友,可以访问私有内容
    friend void goodGayGay::visit();
    //3.告诉编译器 printt全局函数 是 Building类的好朋友,可以访问类中的私有内容
    friend void printt(Building* building);

    public:
    Building(){
        this->m_SittingRoom="客厅";
        this->m_BedRoom="卧室";
    }
    string m_SittingRoom; //客厅
    private:
    string m_BedRoom; //卧室
};
//以下为具体定义函数 
goodGay::goodGay(){
    building=new Building;
}
void goodGay::visit(){
    cout<<"第一个好基友正在访问"<<building->m_SittingRoom<<endl;
    cout<<"第一个好基友正在访问"<<building->m_BedRoom<<endl;
}
goodGayGay::goodGayGay(){
    building=new Building;
}
void goodGayGay::visit(){
    cout<<"第二个好基友正在访问"<<building->m_SittingRoom<<endl;
    cout<<"第二个好基友正在访问"<<building->m_BedRoom<<endl;
}
void goodGayGay::visit2(){
    cout<<"第二个好基友正在第二次访问"<<building->m_SittingRoom<<endl;
    //cout << "第二个好基友正在第二次访问" << building->m_BedRoom << endl;
}
void printt(Building* building){
    cout<<"第三个好基友正在访问: "<<building->m_SittingRoom<<endl;
    cout<<"第三个好基友正在访问: "<<building->m_BedRoom<<endl;
}
void test01(){
    goodGay gg;
    gg.visit();
}
void test02(){
    goodGayGay gg;
    gg.visit();
}
void test03(){
    Building b;
    printt(&b);
}

int main(){
    test01();//friend修饰别的类
    test02();//friend修饰成员函数
    test03();//friend修饰类外定义的函数
    return 0;
}

5-9 知识点1:加号运算符重载

#include<iostream>
using namespace std;
class Person{
public:
    Person(){};
    Person(int a,int b){
        this->m_A=a;
        this->m_B=b;
    }
    //成员函数实现 + 号运算符重载
    Person operator+ (const Person& p){
        Person temp;
        temp.m_A=this->m_A+p.m_A;
        temp.m_B=this->m_B+p.m_B;
        return temp;
    }
    int m_A;
    int m_B;
};
//运算符重载 可以发生函数重载 
Person operator+ (const Person& p2,int val){
    Person temp;
    temp.m_A=p2.m_A+val;
    temp.m_B=p2.m_B+val;
    return temp;
}
void test(){
    Person p1(10,10);
    Person p2(20,20);
    //成员函数方式
    Person p3=p2+p1;  //相当于 p2.operaor+(p1)
    cout<<"mA:"<<p3.m_A<<" mB:"<<p3.m_B<<endl;
    Person p4=p3+10; //相当于 operator+(p3,10)
    cout<<"mA:"<<p4.m_A<<" mB:"<<p4.m_B<<endl;
}
int main(){
    test();
    return 0;
}

5-10 知识点2:输出运算符的

#include<iostream>
using namespace std;
class Person{
    friend ostream& operator<<(ostream& out,Person& p);
    public:

    Person(int a,int b){
        this->m_A=a;
        this->m_B=b;
    }
    private:
    int m_A;
    int m_B;
};

//全局函数实现左移重载
//ostream对象只能有一个
ostream& operator<<(ostream& out,Person& p){
    out<<p.m_A<<p.m_B;
    return out;
}

void test(){
    Person p1(10,20);
    cout<<p1<<"hello world"<<endl; //链式编程
}

int main(){
    test();
    return 0;
}

5-11 知识点3:递增运算符重载

#include<iostream>
using namespace std;
class MyInteger{
    friend ostream& operator<<(ostream& out,MyInteger myint);
public:
    MyInteger(){
        m_Num=0;
    }

    //前置++
    MyInteger& operator++(){
        //先++
        m_Num++;
        //再返回
        return *this;
    }

    //后置++
    MyInteger operator++ (int){
        //先返回
        MyInteger old=*this;
        //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++;
        m_Num++;
        // ++(*this);
        return old;
    }

private:
    int m_Num;
};

ostream& operator<<(ostream& out,MyInteger myint){
    out<<myint.m_Num;
    return out;
}

//前置++ 先++ 再返回
void test01(){
    MyInteger myInt;
    cout<<++myInt<<endl;
    cout<<myInt<<endl;
}

//后置++ 先返回 再++
void test02(){
    MyInteger myInt;
    cout<<myInt++<<endl;
    cout<<myInt<<endl;
}

int main(){
    test01();
    //test02();
    system("pause");
    return 0;
}

5-12 知识点4:赋值运算符重载

#include<bits/stdc++.h>
using namespace std;
class Person{
    public:
    Person(int age){
        //将年龄数据开辟到堆区
        m_Age=new int(age);
    }

    //重载赋值运算符 
    Person& operator=(const Person& p){
        if(m_Age!=NULL){
            delete m_Age;
            m_Age=NULL;
        }
        //编译器提供的代码是浅拷贝
        //m_Age = p.m_Age;

        //提供深拷贝 解决浅拷贝的问题
        m_Age=new int(*p.m_Age);

        //返回自身
        return *this;
    }

    ~Person(){
        if(m_Age!=NULL){
            delete m_Age;
            m_Age=NULL;
        }
    }

    //年龄的指针
    int* m_Age;
};


void test01(){
    Person p1(18);
    Person p2(20);
    Person p3(30);
    p3=p2=p1; //赋值操作
    cout<<"p1的年龄为:"<<*p1.m_Age<<endl;
    cout<<"p2的年龄为:"<<*p2.m_Age<<endl;
    cout<<"p3的年龄为:"<<*p3.m_Age<<endl;
}

int main(){
    test01();

    //int a = 10;
    //int b = 20;
    //int c = 30;

    //c = b = a;
    //cout << "a = " << a << endl;
    //cout << "b = " << b << endl;
    //cout << "c = " << c << endl;

    return 0;
}

7-1 日程安排(多重继承+重载)

已有一个日期类Date,包括三个protected成员数据

int year;
int month;
int day;

另有一个时间类Time,包括三个protected成员数据

int hour;
int minute;
int second;

现需根据输入的日程的日期时间,安排前后顺序,为此以Date类和Time类为基类,建立一个日程类Schedule,包括以下新增成员:

int ID;//日程的ID
bool operator < (const Schedule & s2);//判断当前日程时间是否早于s2

生成以上类,并编写主函数,根据输入的各项日程信息,建立日程对象,找出需要最早安排的日程,并输出该日程对象的信息。

输入格式: 测试输入包含若干日程,每个日程占一行(日程编号ID 日程日期(****//*)日程时间(*::**))。当读入0时输入结束,相应的结果不要输出。

输入样例:

1 2014/06/27 08:00:01
2 2014/06/28 08:00:01
0

输出样例:

The urgent schedule is No.1: 2014/6/27 8:0:1

Code

240527

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

class Date{
protected:
    int year;
    int month;
    int day;
public:
    // Date():year(1970),month(1),day(1){};
    Date(int a,int b,int c):year(a),month(b),day(c){};
    // bool operator<(const Date& other){
    //     if(this->year<other.year) return true;
    //     if(this->year>other.year) return false;
    //     if(this->month<other.month) return true;
    //     if(this->month>other.month) return false;
    //     if(this->day<other.day) return true;
    //     return false;
    // }
    // bool operator>(const Date& other){
    //     if(this->year>other.year) return true;
    //     if(this->year<other.year) return false;
    //     if(this->month>other.month) return true;
    //     if(this->month<other.month) return false;
    //     if(this->day>other.day) return true;
    //     return false;
    // }
    // bool operator==(const Date& other){
    //     if(this->year==other.year && this->month==other.month && this->day==other.day)
    //         return true;
    //     return false;
    // }
};

class Time{
protected:
    int hour;
    int minute;
    int second;
public:
    // Time():hour(0),minute(0),second(0){};
    Time(int a,int b,int c):hour(a),minute(b),second(c){};
    // bool operator<(const Time& other){
    //     if(this->hour<other.hour) return true;
    //     if(this->hour>other.hour) return false;
    //     if(this->minute<other.minute) return true;
    //     if(this->minute>other.minute) return false;
    //     if(this->second<other.second) return true;
    //     return false;
    // }
    // bool operator>(const Time& other){
    //     if(this->hour>other.hour) return true;
    //     if(this->hour<other.hour) return false;
    //     if(this->minute>other.minute) return true;
    //     if(this->minute<other.minute) return false;
    //     if(this->second>other.second) return true;
    //     return false;
    // }
    // bool operator==(const Time& other){
    //     if(this->hour==other.hour && this->minute==other.minute && this->second==other.second)
    //         return true;
    //     return false;
    // }
};

// class Schedule{
//     friend Date;
//     friend Time;
// public:
//     int ID;
//     Date date;
//     Time time;
//     Schedule(int id,int y,int month,int d,int h,int min,int s):ID(id),date(y,month,d),time(h,min,s){};
//     bool operator<(const Schedule& s2){
//         if(this->date<s2.date) return true;
//         if(this->date>s2.date) return false;
//         if(this->time<s2.time) return true;
//         return false;
//     }
// };

class Schedule:Date,Time{
public:
    int ID;
    Schedule(int id,int y,int month,int d,int h,int min,int s):Date(y,month,d),Time(h,min,s),ID(id){};
    bool operator<(const Schedule& s2){
        if(this->year<s2.year) return true;
        if(this->year>s2.year) return false;
        if(this->month<s2.month) return true;
        if(this->month>s2.month) return false;
        if(this->day<s2.day) return true;
        if(this->day>s2.day) return false;
        if(this->hour<s2.hour) return true;
        if(this->hour>s2.hour) return false;
        if(this->minute<s2.minute) return true;
        if(this->minute>s2.minute) return false;
        if(this->second<s2.second) return true;
        return false;
    }
    void print(){
        printf("The urgent schedule is No.%d: %d/%d/%d %d:%d:%d\n",ID,year,month,day,hour,minute,second);
    }
};

int main(){
    Schedule urgent(0,9999,0,0,0,0,0);
    int id,y,month,d,h,min,s;
    while(scanf("%d",&id) && id!=0){
        scanf("%d/%d/%d %d:%d:%d",&y,&month,&d,&h,&min,&s);
        Schedule temp(id,y,month,d,h,min,s);
        if(temp<urgent) urgent=temp;
    }
    urgent.print();
    return 0;
}

7-2 动物世界

Score 10

Author 陈晓梅

Organization 广东外语外贸大学

补充程序 :

1、实现Mammal类的方法

2、由Mammal类派生出Dog类,在Dog类中增加itsColor成员(COLOR类型)

3、Dog类中增加以下方法:

constructors: Dog()Dog(int age)Dog(int age, int weight)Dog(int age, COLOR color)Dog(int age, int weight, COLOR color)~Dog()

accessors: GetColor()SetColor()

Other methods: WagTail()BegForFood() ,并实现以上这些方法 。

提示:类似Speak()WagTail()这些动作,函数体可以是输出一句话。比如:Mammal is spaeking... , The Dog is Wagging its tail...

4、补充主函数的问号部分,并运行程序,检查输出是否合理。

enum COLOR{ WHITE, RED, BROWN, BLACK, KHAKI };

class Mammal
{
    public:
        //constructors
        Mammal();
        Mammal(int age);
        ~Mammal();
        
        //accessors
        int GetAge() const;
        void SetAge(int);
        int GetWeight() const;
        void SetWeight(int);
        
        //Other methods    
        void Speak() const;
        void Sleep() const;        
    protected:
        int itsAge;
        int itsWeight;
};

int main()
{
    Dog Fido;
    Dog Rover(5);
    Dog Buster(6, 8);
    Dog Yorkie(3, RED);
    Dog Dobbie(4, 20, KHAKI);
    Fido.Speak();
    Rover.WagTail();
    cout << "Yorkie is " << ?? << " years old." << endl;
    cout << "Dobbie    weighs " << ?? << " pounds." << endl;   
    return 0;
}

输入格式:

输出格式:

按照程序格式输出。

输入样例:

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

输出样例:

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

Mammal is speaking...
The dog is wagging its tail...
Yorkie is 3 years old.
Dobbie weighs 20 pounds.

Code

240527

#include<bits/stdc++.h>
using namespace std;
enum COLOR{ WHITE,RED,BROWN,BLACK,KHAKI };

class Mammal{
public:
    //constructors
    Mammal(){};
    Mammal(int age):itsAge(age){};
    Mammal(int age,int weight):itsAge(age),itsWeight(weight){};
    ~Mammal(){};

    //accessors
    int GetAge() const{
        return this->itsAge;
    };
    void SetAge(int age){
        this->itsAge=age;
    };
    int GetWeight() const{
        return this->itsWeight;
    };
    void SetWeight(int weight){
        this->itsWeight=weight;
    };

    //Other methods    
    void Speak() const{
        cout<<"Mammal is speaking..."<<endl;
        return;
    };
    void Sleep() const{
        cout<<"Mammal is sleeping..."<<endl;
        return;
    };
protected:
    int itsAge;
    int itsWeight;
};

class Dog:public Mammal{
protected:
    COLOR _color;
public:
    Dog(){};
    Dog(int age):Mammal(age){};
    Dog(int age,int weight):Mammal(age,weight){};
    Dog(int age,COLOR color):Mammal(age),_color(color){};
    Dog(int age,int weight,COLOR color):Mammal(age,weight),_color(color){};
    ~Dog(){};
    void WagTail(){
        cout<<"The dog is wagging its tail..."<<endl;
    }
};

int main(){
    Dog Fido;
    Dog Rover(5);
    Dog Buster(6,8);
    Dog Yorkie(3,RED);
    Dog Dobbie(4,20,KHAKI);
    Fido.Speak();
    Rover.WagTail();
    cout<<"Yorkie is "<<Yorkie.GetAge()<<" years old."<<endl;
    cout<<"Dobbie weighs "<<Dobbie.GetWeight()<<" pounds."<<endl;
    return 0;
}

7-3 打印点、圆、圆柱信息

定义平面二维点类CPoint,有数据成员x坐标,y坐标,函数成员(构造函数、虚函数求面积GetArea, 虚函数求体积函数GetVolume、输出点信息函数print)。

CPoint类派生出圆类Cirle类(新增数据成员半径radius),函数成员(构造函数、求面积GetArea,虚函数求体积函数GetVolume、输出圆面积信息函数print)。

再由Ccirle类派生出圆柱体Ccylinder类(新增数据成员高度height),函数成员(构造函数、求表面积GetArea ,求体积函数GetVolume、输出圆柱体体积信息函数print)。在主函数测试这个这三个类。

打印数据保留小数点后2位

输入格式:

点的:x坐标 点的:y坐标 圆半径 圆柱高

输出格式:

点信息 圆面积 圆柱体积

输入样例:

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

1
2
3
4

输出样例:

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

CPoint:1,2
CirleArea:28.26
CcylinderVolume:113.04

Code

240528

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

class CPoint{
protected:
    int x,y;
public:
    CPoint(int a,int b):x(a),y(b){};
    virtual void GetArea(){};
    virtual void GetVolume(){};
    void print(){
        printf("CPoint:%d,%d\n",x,y);
    }
};

class CCircle:public CPoint{
protected:
    int radius;
public:
    CCircle(int a,int b,int c):CPoint(a,b),radius(c){};
    void GetArea() override{
        printf("CirleArea:%.2lf\n",3.14*radius*radius);
    }
    void GetVolume() override{};
};

class Ccylinder:public CCircle{
protected:
    int height;
public:
    Ccylinder(int a,int b,int c,int d):CCircle(a,b,c),height(d){};
    void GetArea() override{
        // printf("%.2lf\n",3.14*radius*radius*2+2*3.14*radius*height);
        printf("CirleArea:%.2lf\n",3.14*radius*radius);
    }
    void GetVolume() override{
        printf("CcylinderVolume:%.2lf\n",3.14*radius*radius*height);
    }
};


int main(){
    int a,b,c,d;
    cin>>a>>b>>c>>d;
    Ccylinder t(a,b,c,d);
    t.print();
    t.GetArea();
    t.GetVolume();
    return 0;
}

7-4 单继承中的构造函数与析构函数

编写代码实现一个表示点的父类Dot和一个表示圆的子类Cir,求圆的面积。

Dot类有两个private数据成员 float x,y;

Cir类新增一个private的数据成员半径float r 和一个public的求面积的函数getArea( );

主函数已经给出,请编写DotCir类。

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

输入格式:

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

输出格式:

输出圆的面积,小数点后保留2位有效数字,注意:const double PI=3.14,面积=PI*r*r

输入样例:

在这里给出一组输入。例如圆的中心点为原点(0,0),半径为3:

0 0 4

输出样例:

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

Dot constructor called
Cir constructor called
50.24
Cir destructor called
Dot destructor called

Code

240528

#include<iostream>
using namespace std;
const double PI=3.14;

class Dot{
private:
    float x,y;
public:
    Dot(int a,int b):x(a),y(b){
        cout<<"Dot constructor called"<<endl;
    };
    ~Dot(){
        cout<<"Dot destructor called"<<endl;
    }
};

class Cir:public Dot{
private:
    float r;
public:
    Cir(int a,int b,int c):Dot(a,b),r(c){
        cout<<"Cir constructor called"<<endl;
    };
    float getArea(){
        return PI*r*r;
    }
    ~Cir(){
        cout<<"Cir destructor called"<<endl;
    }
};

int main(){
    int a,b,c;
    cin>>a>>b>>c;
    Cir t(a,b,c);
    cout<<t.getArea()<<endl;
    return 0;
}

7-5 定义一个Time类

定义一个时间类,能够提供和设置由时、分、秒组成的时间,并按照如下的格式输出时间: 08-09-24 12-23-59

输入格式:

请在这里写输入格式。例如: 12 8 9 8 24 59

输出格式:

请在这里描述输出格式。例如: 12-08-09 08-24-59

输入样例:

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

8 9 24

输出样例:

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

08-09-24

Code

240528

#include<iostream>
using namespace std;
int main(){
    int a,b,c;
    while(scanf("%d %d %d",&a,&b,&c)!=EOF){
        printf("%02d-%02d-%02d\n",a,b,c);
    }
    return 0;
}

7-6 绩点计算 - 《C++编程基础及应用》- 习题3-3

某大学的GPA(绩点)计算规则如下:

课程百分制成绩90分对应绩点4.0,超过90分的,按90分计;如不足90分,则课程绩点 = 4.0 * 分数/90。 学生综合绩点按该生已修的各门课程绩点结合学分加权平均而得。 现有步步同学入学后的已修课程(共5门)成绩表如下,请编程计算其GPA。

输入格式:

第1门课程百分制分数 学分

第2门课程百分制分数 学分

第3门课程分制分数 学分

第4门课程百分制分数 学分

第5门课程百分制分数 学分

说明:百分制分数和学分均为整数。

输出格式:

请参考输出样例。其中,GPA值保留两位小数。

输入样例:

78 3
91 5
65 4
95 3
60 2

输出样例:

GPA:3.49

提示:从键盘读取输入的方法,请参考教材后续章节。

Code

240528

#include<iostream>
using namespace std;
int main(){
    int a[5],b[5];
    double c[5];
    double a_sum=0;
    int b_sum=0;
    for(int i=0;i<5;i++){
        scanf("%d %d",&a[i],&b[i]);
        if(a[i]>90) a[i]=90;
        c[i]=4.0*a[i]/90;
        b_sum+=b[i];
        a_sum+=c[i]*b[i];
    }
    printf("GPA:%.2lf\n",a_sum/b_sum);
    return 0;
}

7-7 菲姐游泳 - 《C++编程基础及应用》- 习题3-5

游泳奥运冠军菲姐刻苦训练,从早上a时b分开始下水训练,直到当天的c时d分结束。请编程计算:菲姐当天一共训练多少小时多少分钟?

输入格式:

一行之内输入以空格分隔的4个非负整数,分别对应a,b,c,d。其中,0 ≤a<c ≤24;b和d均不大于60。

输出格式:

h:m。其中,整数h表示小时数,整数m表示分钟数,m应小于60。

输入样例:

6 30 23 20

输出样例:

16:50

Code

240528

#include<iostream>
using namespace std;
int main(){
    int a,b,c,d;
    cin>>a>>b>>c>>d;
    c-=a;
    d-=b;
    if(d<0){
        d+=60;
        c--;
    }
    printf("%d:%d\n",c,d);
    return 0;
}

Basic CPP Homework
https://acm.nanyan.cc/posts/a313.html
作者
nanyan
发布于
2024年4月1日
许可协议