【C++】C++面向对象练习题

利用多态机制完成以下题目

现需要一个理财程序,其中包含四个类,分别为投资(Investment)、储蓄(Saving)、基金(Fund)和理财人(Person),储蓄和基金为两种具体投资,都有确定的投资金额(m_capital),但它们年底结算(setrle)的方式不同。储蓄的结算方式如下:

m_capital = m_capital * (1+1.78/100);

基金的结算方式如下:

m_capital =m_capital * (rand()%20 +90)/100;

理财人实例化时确定本金m_cashFlow。理财人通过其成员函数addInvest 添加具体投资,将新建的投资类实例的地址保存在vector 类型的成员mv_invests中,并从本金中减去投资额。一年后,理财人通过其成员函数settle结算所有投资,将投资额返回本金。实现效果如下:

//初始本金十万元

Person Wang(100000);

//储蓄、基金分别投资五万、两万

Wang.addInvest(Saving(50000));

Wang.addInvest (Fund(20000));

//年底全部结算转入本金

cout<<Wang.settle()<<endl;

请据此给出投资、储蓄、基金、理财人这四个类的定义,并利用上述代码进行测试。

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

// 投资基类
class Investment {
public:
    // 构造函数,初始化投资金额
    Investment(double capital) : m_capital(capital) {}

    // 获取投资金额的方法,声明为 const,不改变对象状态
    double getCapital() const {
        return m_capital;
    }

    // 纯虚函数,用于派生类实现投资结算逻辑
    virtual double settle() = 0;

protected:
    double m_capital; // 投资金额
};

// 储蓄类,继承自投资基类
class Saving : public Investment {
public:
    // 构造函数,调用基类构造函数初始化投资金额
    Saving(double capital) : Investment(capital) {}

    // 实现投资结算逻辑
    double settle() override {
        m_capital *= (1 + 1.78 / 100); // 年底结算方式:本金增加 1.78%
        return m_capital; // 返回年底结算后的本金
    }
};

// 基金类,继承自投资基类
class Fund : public Investment {
public:
    // 构造函数,调用基类构造函数初始化投资金额
    Fund(double capital) : Investment(capital) {}

    // 实现投资结算逻辑
    double settle() override {
        m_capital *= (rand() % 20 + 90) / 100.0; // 年底结算方式:本金按 90%~109% 之间的随机比例变动
        return m_capital; // 返回年底结算后的本金
    }
};

// 理财人类
class Person {
public:
    // 构造函数,初始化理财人本金
    Person(double cashFlow) : m_cashFlow(cashFlow) {}

    // 添加投资,将投资金额从本金中扣除,并保存投资对象的指针
    void addInvest(Investment* invest) {
        m_cashFlow -= invest->getCapital(); // 本金减去投资金额
        mv_invests.push_back(invest); // 将投资对象指针保存到投资对象容器中
    }

    // 年底结算,对所有投资进行结算,并将结算后的金额返回到本金中
    double settle() {
        double totalCapital = 0; // 总投资金额
        // 遍历所有投资对象,进行结算
        for (auto& invest : mv_invests) {
            totalCapital += invest->settle(); // 累加所有投资的结算金额
        }
        m_cashFlow += totalCapital; // 将结算后的金额追加到本金中
        return m_cashFlow; // 返回年底结算后的本金
    }

    // 公有接口,用于获取投资对象容器
    const std::vector<Investment*>& getInvests() const {
        return mv_invests; // 返回投资对象容器
    }

private:
    double m_cashFlow; // 理财人的本金
    std::vector<Investment*> mv_invests; // 投资对象容器
};

int main() {
    srand(time(nullptr)); // 初始化随机数种子

    Person Wang(100000); // 创建一个理财人对象,初始本金为 100000
    Wang.addInvest(new Saving(50000)); // 添加一个储蓄投资,投资金额为 50000
    Wang.addInvest(new Fund(20000)); // 添加一个基金投资,投资金额为 20000

    std::cout << "年底结算后的本金:" << Wang.settle() << std::endl; // 输出年底结算后的本金

    // 释放动态分配的内存
    for (auto& invest : Wang.getInvests()) {
        delete invest;
    }

    return 0;
}

已知Point类和LineString折线类定义如下,请写出LineString类的各个成员函数的实现。

class Point { public:double x, y; };

class LineString {//由多个点组成的线串类,由n个点组成的折线包含n-1个线段

public:

LineString(Point* pnts, int num); //构造函数,通过传入点数组来构造

LineString(const LineString& another); //复制构造函数

~LineString();//析构函数

LineString& operator=(const LineString& rhs);//赋值函数

Point& operator[](int index);//返回线串中第index个点的引用

private:

Point* m_data;//用于保存组成线串的点

int m_num;// 线串中点的数量

};

#include <iostream>
#include <cassert> // 引入 assert 头文件以使用断言

using namespace std;

// 定义点类
class Point {
public:
    double x, y;

    // 默认构造函数
    Point() : x(0), y(0) {}

    // 带参构造函数
    Point(double _x, double _y) : x(_x), y(_y) {}
};

// 定义线串类
class LineString {
public:

    // 默认构造函数
    LineString() : m_data(nullptr), m_num(0) {}

  
    // 构造函数,通过传入点数组来构造线串
    LineString(Point* pnts, int num) {
        m_num = num; // 设置线串中点的数量
        m_data = new Point[num]; // 分配动态内存用于存储点数组
        for (int i = 0; i < num; ++i) {
            m_data[i] = pnts[i]; // 复制传入的点数组到线串的内部存储中
        }
    }

    // 复制构造函数,用于创建新线串对象时复制另一个线串对象的内容
    LineString(const LineString& another) {
        m_num = another.m_num; // 复制另一个线串对象中的点数量
        m_data = new Point[m_num]; // 分配动态内存用于存储新线串对象的点数组
        for (int i = 0; i < m_num; ++i) {
            m_data[i] = another.m_data[i]; // 复制另一个线串对象的点数组到新线串对象的内部存储中
        }
    }

    // 析构函数,用于释放线串对象的动态内存
    ~LineString() {
        delete[] m_data;
    }

    // 赋值函数,用于将一个线串对象赋值给另一个线串对象
    LineString& operator=(const LineString& rhs) {
        if (this == &rhs) return *this; // 检查自赋值情况
        delete[] m_data; // 释放原有的动态内存
        m_num = rhs.m_num; // 复制另一个线串对象的点数量
        m_data = new Point[m_num]; // 分配动态内存用于存储新线串对象的点数组
        for (int i = 0; i < m_num; ++i) {
            m_data[i] = rhs.m_data[i]; // 复制另一个线串对象的点数组到新线串对象的内部存储中
        }
        return *this;
    }

    // 重载下标运算符,用于访问线串对象中的点数组中的某个点
    Point& operator[](int index) {
        assert(index >= 0 && index < m_num); // 使用断言确保索引合法
        return m_data[index];
    }

private:
    Point* m_data; // 用于保存线串对象中的点数组
    int m_num; // 线串中点的数量
};

int main() {
    // 创建一些点对象
    Point p1(1.0, 1.0);
    Point p2(2.0, 2.0);
    Point p3(3.0, 3.0);

    // 创建一个点数组
    Point pnts[] = { p1, p2, p3 };

    // 使用点数组构造一个线串对象
    LineString ls(pnts, 3);

    // 测试复制构造函数,将已有的线串对象复制给新线串对象
    LineString ls_copy = ls;

    // 测试赋值函数,将已有的线串对象赋值给另一个线串对象
    LineString ls_assigned;
    ls_assigned = ls;

    // 输出线串对象中各个点的坐标
    for (int i = 0; i < 3; ++i) {
        cout << "Point " << i + 1 << ": (" << ls[i].x << ", " << ls[i].y << ")" << endl;
    }

    return 0;
}

已知String类定义如下:

class String

{

public:

String(const char*str=NULL);//通用拷贝函数

String(const String&another);//拷贝构造函数

~String();//析构函数

String &operator=(const String&rhs);//赋值函数

operator const char *();//强制转换

private:

char *m_data;//用于保存字符串

};

请写出String类的各个成员函数的实现

#include <iostream>
#include <cstring>
#pragma warning(disable:4996)


class String
{
public:
    String(const char* str = nullptr); // 通用拷贝函数
    String(const String& another);     // 拷贝构造函数
    ~String();                         // 析构函数
    String& operator=(const String& rhs); // 赋值函数
    operator const char* ();            // 强制转换

private:
    char* m_data; // 用于保存字符串  
};

String::String(const char* str) {
    if (str == nullptr) {
        m_data = new char[1];
        *m_data = '\0';
    }
    else {
        m_data = new char[strlen(str) + 1];
        strcpy(m_data, str);
    }
}

String::String(const String& another) {
    m_data = new char[strlen(another.m_data) + 1];
    strcpy(m_data, another.m_data);
}

String::~String() {
    delete[] m_data;
}

String& String::operator=(const String& rhs) {
    if (this != &rhs) {
        delete[] m_data;
        m_data = new char[strlen(rhs.m_data) + 1];
        strcpy(m_data, rhs.m_data);
    }
    return *this;
}

String::operator const char* () {
    return m_data;
}

int main() {
    // 测试构造函数
    String s1("Hello, world!");
    String s2(s1); // 使用拷贝构造函数
    std::cout << "s1: " << s1 << std::endl;
    std::cout << "s2: " << s2 << std::endl;

    // 测试赋值函数
    String s3;
    s3 = s1; // 使用赋值函数
    std::cout << "s3: " << s3 << std::endl;

    return 0;
}

定义抽象类型Shape ,包含计算图形面积的纯虚函数Area ,由他派生三个类:Circle。Rectangle、Trapezoid 另外重载运算符+ 以支持如下测试代码

Circle c(10);

Rectangle r(4,5);

Trapezoid t(5,6,2);

double area=c+r+t;//计算c r t的面积和

提示:需要两个互为重载的运算符函数,且一个函数的两个参数为Shape的引用,另一个函数的两个参数为double和Shape的引用

#include <iostream>

class Shape {
public:
    virtual double Area() const = 0; // 纯虚函数
    virtual ~Shape() {} // 虚析构函数,确保正确释放资源
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double Area() const override {
        return 3.14 * radius * radius;
    }
};

class Rectangle : public Shape {
private:
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double Area() const override {
        return width * height;
    }
};

class Trapezoid : public Shape {
private:
    double a, b, h;
public:
    Trapezoid(double a1, double b1, double h1) : a(a1), b(b1), h(h1) {}
    double Area() const override {
        return (a + b) * h / 2;
    }
};

// 重载运算符+,两个参数为Shape的引用
double operator+(const Shape& s1, const Shape& s2) {
    return s1.Area() + s2.Area();
}

// 重载运算符+,一个参数为double,另一个参数为Shape的引用
double operator+(double d, const Shape& s) {
    return d + s.Area();
}

int main() {
    Circle c(10);
    Rectangle r(4, 5);
    Trapezoid t(5, 6, 2);

    // 计算c r t的面积和
    double area = c + r + t;
    std::cout << "Total area: " << area << std::endl;

    return 0;
}

设计复数类Complex ,包含double类型的实部和虚部,实现运算符+-*以及输出符号的重载 。Complex的调用如main函数所示。

#include<iostream>

using namespace std;

void main() {

Complex c1(2.0, 3.0);

Complex c2(1.0, 2.0);

cout<<c1+c2<<endl;

cout<<c1-c2<<endl;

cout<<c1*c2<<endl;

}

#include <iostream>
using namespace std;

class Complex {
private:
    double real;
    double imag;

public:
    // 构造函数
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

    // 重载加法运算符+
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }

    // 重载减法运算符-
    Complex operator-(const Complex& other) const {
        return Complex(real - other.real, imag - other.imag);
    }

    // 重载乘法运算符*
    Complex operator*(const Complex& other) const {
        double r = real * other.real - imag * other.imag;
        double i = real * other.imag + imag * other.real;
        return Complex(r, i);
    }

    // 重载输出运算符<<
    friend ostream& operator<<(ostream& out, const Complex& c) {
        out << "(" << c.real << ", " << c.imag << "i)";
        return out;
    }
};

int main() {
    Complex c1(2.0, 3.0);
    Complex c2(1.0, 2.0);

    cout << c1 + c2 << endl;  // 输出 c1 + c2 的结果
    cout << c1 - c2 << endl;  // 输出 c1 - c2 的结果
    cout << c1 * c2 << endl;  // 输出 c1 * c2 的结果

    return 0;
}
  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WiIsonEdwards

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值