计算机二级c++备考

一、计划

1.进入网址 启程网络 - 新简约软件开发工作室 往下滑找到下图;

2.下载题库,可以选择上面网站的,也可以去未来教育(没有广告tb/pxx)

二、练习 

1.函数重写(覆盖)


//语句①②哪个是有二义性
class B1 {
public:
    void fun1(){}
    void fun2(int){}
};
class B2 {
public:
    void fun1(){}
    void fun2(){}
};
class D : public B1, public B2 {//声明了一个名为 D 的类,它是从 B1 和 B2 两个基类派生而来的。public 表示采用公有继承方式,这意味着基类的 public 成员在派生类中仍然是 public 的。
public:
    void fun1(){} //定义了一个名为 fun1 的成员函数,返回值为 void,不接受任何参数,函数体为空。这个函数会覆盖从基类 B1 和 B2 继承来的 fun1 函数。
};
int main() {
    D obj;
    obj.fun1();    //①调用 obj 对象的 fun1 函数。由于 D 类中重写了 fun1 函数,所以这里调用的是 D 类自己定义的 fun1 函数。
    obj.fun2(10);  //②这行代码会引发编译错误。因为 D 类从 B1 和 B2 继承了两个不同版本的 fun2 函数,一个接受 int 类型参数(来自 B1),另一个不接受参数(来自 B2),编译器无法确定调用哪个版本的 fun2 函数,产生了二义性。
    return 0;
}
class B1 {
public:
    int val;
    void fun1() {
        std::cout << "B1::fun1 called" << std::endl;
    }
};
class B2 {
public:
    void fun1() {
        std::cout << "B2::fun1 called" << std::endl;
    }
private:
    int val;
};
class D : public B1, public B2 {
public:
    void fun1() {
        std::cout << "D::fun1 called" << std::endl;
    }
};
int main() {
    D obj;
    obj.val = 1;//有二义性,编译器无法确定你要访问的是 B1 类中的 val 还是 B2 类中的 val,所以会产生二义性错误。虽然 B2 中的 val 是私有成员,不能直接访问,但从语法二义性角度有影响,可改为 obj.B1::val = 1; 用了作用域解析运算符 ::,明确告诉编译器,你要访问的是从 B1 类继承过来的 val 成员变量,这样就消除了二义性,让代码能够正确编译和访问到想要的成员 
    obj.fun1(); // 类自己定义了 fun1 函数,在调用 obj.fun1() 时,优先调用自身定义的函数,不会产生二义性。
    return 0;
}

2. 函数参数传递

#include <iostream> //引入输入输出流头文件,用于实现控制台的输入输出功能
using namespace std; //使用 std 命名空间,这样在后续代码中可以直接使用 cout 等标准库中的标识符,而不需要写 std:: 前缀

class Point 
{
public: //访问修饰符后的内容可以在类外部被访问
    Point() { x = y = 0; } //默认构造函数,将成员变量 x 和 y 初始化为 0
    Point(int i, int j) { x = i; y = j; } //带参数的构造函数,用于初始化 x 和 y 为传入的参数值
    void copy(Point &m); //函数声明,用于复制一个 Point 对象的坐标值
    void setxy(int i, int j) { x = i; y = j; } //函数用于设置 Point 对象的坐标值
    void print() { cout << x << "," << y << " "; } //在控制台输出 Point 对象的坐标
private:
    int x, y; //这两个成员变量只能在类内部被访问和操作
};

void Point::copy(Point &m) //实现了 Point 类的 copy 函数,通过引用参数 m 来获取另一个 Point 对象的坐标,并将其赋值给自己的 x 和 y 成员变量。
{
    x = m.x;
    y = m.y;
}

void fun(Point &m1, Point m2) //定义了一个名为 fun 的函数,接受一个 Point 对象的引用 m1 和一个 Point 对象 m2
//在函数内部,通过调用 setxy 函数分别修改 m1 和 m2 的坐标。注意由于 m2 是值传递,对 m2 的修改不会影响到外部传入的实参。
{
    m1.setxy(12, 15);
    m2.setxy(22, 25);
}

int main()
{
    Point p(5, 7), q; //创建了两个 Point 对象 p 和 q,p 初始坐标为 (5, 7),q 使用默认构造函数初始化。
    q.copy(p); //调用 q.copy(p) 将 p 的坐标复制给 q。
    fun(p, q); //调用 fun(p, q) 函数,该函数会修改 p 的坐标为 (12, 15),但 q 作为值传递的参数,其原始值不受函数内部修改的影响。
    p.print();//输出结果是 12,15 
    q.print(); //输出结果是 5,7
    return 0;
}
#include <iostream>
using namespace std;

class Point
{
public:
    Point() { x = y = 0; }
    Point(int i, int j) { x = i; y = j; }
    void copy(Point *m);
    void setxy(int i, int j) { x = i; y = j; }
    void print() { cout << x << ',' << y << ','; }
private:
    int x, y;
};

void Point::copy(Point *m)//定义了之前在类中声明的 copy 函数。这里 Point:: 表示该函数是 Point 类的成员函数。函数功能是将指针 m 所指向的 Point 对象的 x 和 y 坐标值分别赋给当前对象的 x 和 y 成员变量。
{
    x = m->x;
    y = m->y;
}

void fun(Point m1, Point *m2)//定义一个普通函数 fun,接受一个 Point 类的对象 m1 和一个指向 Point 类对象的指针 m2 作为参数
{
    m1.setxy(12, 15);
    m2->setxy(22, 25);
}

int main()
{
    Point p(5, 7), q;
    q.copy(&p);
    fun(p, &q);//调用 fun 函数,将 p 按值传递,q 的地址传递给函数。在函数内部,p 的副本被修改,但 p 本身不受影响,而 q 的坐标被修改为 (22, 25)
    p.print();//5 7
    q.print();//22 25
    return 0;
}

3.插入新分数,淘汰最小分数 

FigureSkating.h

#pragma once //这是一个预处理指令,用于确保头文件只被编译一次,避免重复包含。
#pragma warning(disable:4996) //这是一个预处理指令,用于禁用编译器的特定警告信息,这里禁用的是警告编号为 4996 的警告。

const int  NUM = 8;//定义了一个常量 NUM,其值为 8,用于表示数组的大小。
class CFigureSkating //定义了一个名为CFigureSkating的类(花样滑冰)
{
private:
	double score[NUM];//类的私有成员变量,定义了一个包含 NUM 个元素的双精度浮点数数组 score,用于存储选手的得分。

public:
	CFigureSkating(void);//类的默认构造函数声明,用于创建 CFigureSkating 类的对象,没有参数。
	CFigureSkating(double []);//类的带参数构造函数声明,接受一个双精度浮点数数组作为参数,用于初始化 score 数组。
	~CFigureSkating(void);//类的析构函数声明,用于在对象销毁时进行清理工作。
	double QualifyingRound(double);//类的成员函数声明,接受一个双精度浮点数作为参数,返回一个双精度浮点数,表示被淘汰的分数。

	void PrintScore();//类的成员函数声明,用于输出选手的得分。

};

main.cpp

#include "FigureSkating.h" //包含自定义的头文件 FigureSkating.h
#include <iostream> //#include <iostream> 包含标准输入输出流的头文件,以便使用 cin 和 cout 进行输入输出操作。
using namespace std; //这行代码使用了 std 命名空间,这样在使用 std 命名空间中的标识符(如 cout、cin 等)时就不需要显式地加上 std:: 前缀。

extern void writeToFile(const char *);//这行代码声明了一个外部函数 writeToFile,该函数接受一个 const char * 类型的参数,返回值为 void。extern 关键字表示这个函数是在其他文件中定义的。

int main()
{
	double currentScore[NUM] = {96.5, 93.7, 85.4, 82.1, 74.3, 70.7, 65.4, 32.1}; //定义了一个包含 NUM 个元素的双精度浮点数数组 currentScore,并对其进行初始化。NUM 是在 FigureSkating.h 中定义的常量。
	double newScore; //用于存储用户输入的新分数
	CFigureSkating fs(currentScore); //创建了一个 CFigureSkating 类的对象 fs,并使用 currentScore 数组作为参数调用构造函数进行初始化。
	cout << "花样滑冰晋级赛成绩单" << endl; //
	cout << "目前各晋级分数是:";
	fs.PrintScore();//调用 CFigureSkating 类的 PrintScore 成员函数,输出当前选手的得分
	cout <<"-------------------------------------" << endl
		<< "请输入当前选手得分:";
	cin >> newScore; 
	while (newScore != -1)
	{
		cout << "现在被淘汰的分数是:";
		cout << fs.QualifyingRound(newScore) << endl;//调用 CFigureSkating 类的 QualifyingRound 成员函数,传入用户输入的新得分,并输出该函数的返回值,即被淘汰的分数
		cout << "最新各晋级分数是:";
		fs.PrintScore();//调用 CFigureSkating 类的 PrintScore 成员函数,输出当前选手的得分。
		cout << "-------------------------------------" << endl
			<< "请输入当前选手得分:";
		cin >> newScore;//从标准输入读取用户输入的新得分,并存储到 newScore 变量中。
	}
	writeToFile("");//调用外部函数 writeToFile,传入一个空字符串作为参数。
    return 0;
}

FigureSkating.cpp

#include "FigureSkating.h"
#include <iostream>
using namespace std;

CFigureSkating::CFigureSkating(void)//CFigureSkating 类的默认构造函数定义。

{
	for (int i = 0; i < NUM; i++) //构造函数的实现,将 score 数组的所有元素初始化为 0.0。
		score[i] = 0.0;
}

CFigureSkating::CFigureSkating(double initScore[NUM])//CFigureSkating 类的带参数构造函数定义,接受一个双精度浮点数数组作为参数。
{
	for (int i = 0; i < NUM; i++)//构造函数的实现,将参数数组 initScore 的元素依次赋值给 score 数组。

		score[i] = initScore[i];
}

CFigureSkating::~CFigureSkating(void)//CFigureSkating 类的析构函数定义,这里为空实现,因为没有需要释放的资源。

{
}

double CFigureSkating::QualifyingRound(double newScore)//CFigureSkating 类的 QualifyingRound 成员函数定义,接受一个双精度浮点数作为参数。
{
	int i, insertPosition = NUM;//定义了两个局部变量,insertPosition 用于记录新得分的插入位置,初始化为 NUM,
	double outScore;//outScore 用于记录被淘汰的分数
	for (i = 0; i < NUM; i++)//遍历 score 数组,找到新得分应该插入的位置,如果新得分大于某个元素,则将该位置记录到 insertPosition 中,并跳出循环
		if (newScore > score[i])
		{
			insertPosition = i;
			break;
		}
	//********333********
		if (insertPosition != NUM)//如果插入的位置不是数组的大小,即就是可以插进数组里面,则直接
			{
				outScore = score [NUM-1];//先将数组最后一个元素,也是最小的元素给淘汰掉
				for (i = NUM - 1; i > insertPosition; i--)//从数组最后一个元素往前遍历
					score [i] = score [i - 1];//将前一个的元素赋给后一个元素
					score [insertPosition] = newScore;//将新的分数再插入到要插入的位置
			}
		else//否则,要插入的位置是数组的大小,那我们就直接将新拿到的分给淘汰掉
			outScore = newScore;
	//********666********
	return outScore;//返回淘汰的分数
}

void CFigureSkating::PrintScore()//CFigureSkating 类的 PrintScore 成员函数定义。
{
	for (int i = 0; i < NUM; i++)//遍历 score 数组,将数组中的元素依次输出,每个元素之间用制表符分隔,最后输出换行符
		cout << score[i] << '\t';
	cout << endl;
}

4.指针 

#include<iostream>
using namespace std;

class Vehicle {
public:
    void run() { cout << "vehicle run!" << endl; };
    void stop() { cout << "vehicle stop!" << endl; };
};

class Motorcar : public Vehicle {
public:
    void run() { cout << "motorcar run!" << endl; };
    void stop() { cout << "motorcar stop!" << endl; };
};

int main() {
    Motorcar m;
    m.run();
    Vehicle* vp = &m;//创建一个指向 Vehicle 类的指针 vp ,并让它指向 Motorcar 对象 m ,因为 Motorcar 是 Vehicle 的子类,存在类型兼容关系,可以这样赋值
    vp->stop();//过指针 vp 调用 stop 函数,这里由于没有使用虚函数(C++ 中通过 virtual 关键字声明虚函数),所以调用的是指针类型(Vehicle 类)的 stop 函数,输出 "vehicle stop!" 。
    return 0;
}

5.派生类构造函数、成员函数重写

#include <iostream>
// 包含输入输出流库,用于使用 cout 进行输出操作

#include <string>
// 包含字符串库,用于使用 string 类型

using namespace std;
// 使用标准命名空间,这样在使用标准库中的类和函数时可以省略 std:: 前缀

class Surname
{
// 定义一个名为 Surname 的类,用于表示姓氏

public:
    Surname(string s) {
        // 定义 Surname 类的构造函数,接受一个 string 类型的参数 s
        SetSurname(s);
        // 调用 SetSurname 方法,将传入的参数 s 设置为姓氏
    }

    void SetSurname(string s)
    {
        // 定义一个公共成员函数 SetSurname,用于设置姓氏
        surname = s;
        // 将传入的参数 s 赋值给类的保护成员变量 surname
    }

    void Print() const
    {
        // 定义一个公共的常量成员函数 Print,用于输出姓氏
        cout << surname << " ";
        // 使用 cout 输出姓氏,并在后面添加一个空格
    }

protected:
    string surname;
    // 定义一个保护成员变量 surname,用于存储姓氏
};

class Name : public Surname
{
// 定义一个名为 Name 的类,它是 Surname 类的公有派生类,用于表示姓名

public:
    Name(string s, string n) : Surname(s)
    {
        // 定义 Name 类的构造函数,接受两个 string 类型的参数 s 和 n
        // 使用成员初始化列表调用基类 Surname 的构造函数,将 s 作为姓氏传递给基类
        //Name 类继承自 Surname 类,意味着 Name 类包含了 Surname 类的特征,其中姓氏就是 Surname 类所管理的核心属性。当创建 Name 对象时,它需要初始化从 Surname 类继承来的姓氏部分。通过将 s 传递给基类 Surname 的构造函数,我们可以确保 Name 对象中的姓氏属性得到正确的初始化。
        SetName(n);
        // 调用 SetName 方法,将传入的参数 n 设置为名字
    }

    void SetName(string n)
    {
        // 定义一个公共成员函数 SetName,用于设置名字
        name = n;
        // 将传入的参数 n 赋值给类的私有成员变量 name
    }

    void Print() const
    {
        // 定义一个公共的常量成员函数 Print,用于输出完整的姓名
        Surname::Print();
        // 调用基类 Surname 的 Print 方法,输出姓氏
        cout << name << "\n";
        // 使用 cout 输出名字,并换行
    }

private:
    string name;
    // 定义一个私有成员变量 name,用于存储名字
};

int main()
{
    // 定义程序的入口函数 main

    Name onePerson("zhang", "yu");
    // 创建一个 Name 类的对象 onePerson,传入姓氏 "zhang" 和名字 "yu"

    onePerson.Print();
    // 调用 onePerson 对象的 Print 方法,输出完整的姓名

    return 0;
    // 程序正常结束,返回 0
}

6.判断一个数是否为两个阶乘之和的算法

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

// 定义Factorial类,用于判断一个数是否为两个阶乘之和
class Factorial
{
public:
    // 构造函数,接收一个整数target,将其赋值给成员变量max
    Factorial(int target){max = target; }
    // 判断是否是两个阶乘之和的成员函数
    bool IsFactorialSum();
    // 打印结果的成员函数,输出max = left! + right! 的形式
    void Print(){
        cout<<this->max<<"="<<this->left<<"!+"<<this->right<<"!"<<endl;
    }
private:
    int max;  // 目标整数,即要判断是否为两个阶乘之和的数
    int left,right;  // 找到的两个阶乘数,满足 left! + right! = max
    int factorialSet[11];  // 保存阶乘数的数组,最多保存10个阶乘值
};

// 声明一个将结果写入文件的函数,这里只是声明,未实现具体功能
void writeToFile(const string);

// 实现Factorial类的IsFactorialSum成员函数
bool Factorial::IsFactorialSum()
{
    int i=1, n=1;
    // 计算从1开始的各个阶乘,保存在数组factorialSet中
    while (n<max)
    {
        factorialSet[i]=n;
        n*=(++i);
    }

    // 双重循环遍历阶乘数组,寻找满足两个阶乘之和等于max的组合
    for (int j = 1; j <= i; j++) {
        for (int k = 1; k <= i; k++) {
            if (factorialSet[j] + factorialSet[k] == max) {
                left = j;
                right = k;
                return true;  // 找到满足条件的组合,返回true
            }
        }
    }
    return false;  // 未找到满足条件的组合,返回false
}

// 主函数,程序的入口点
int main()
{
    int target;
    cout<<"请输入一个整数,回车键结束:";
    cin>>target;  // 从标准输入读取一个整数,赋值给target
    Factorial obj(target);  // 创建Factorial类的对象obj,传入目标整数target

    // 调用IsFactorialSum函数判断是否为两个阶乘之和
    if (obj.IsFactorialSum())
        obj.Print();  // 如果是,调用Print函数输出结果
    else
        cout<<"给定的数不是两个阶乘之和"<<endl;  // 如果不是,输出提示信息

    writeToFile("");  // 调用writeToFile函数,这里传入空字符串
    return 0;  // 程序正常结束,返回0
}

// 这里可以实现writeToFile函数,但目前只是占位
void writeToFile(const string) {
    // 可以在这里添加将结果写入文件的具体代码
}

7.有疑惑

#include <iostream> // 引入输入输出流头文件,用于使用cin、cout等输入输出操作
using namespace std; // 使用标准命名空间,这样在使用标准库中的对象和函数时可以省略std::前缀

class Integer{ // 定义一个名为Integer的类
public: // 声明公有成员,外部可以访问这些成员
    Integer(int val=0):value(val){} // 构造函数,带有默认参数0,用于初始化类中的value成员变量
    Integer operator+(Integer itg) { // 对运算符+进行重载,使得Integer类的对象之间可以像内置类型(如int)一样使用+运算符进行加法运算。在这个函数中,它将当前对象(调用该运算符函数的对象)的value成员与传入对象itg的value成员相加,并返回相加的结果
//在实际编程中,如果有多个Integer类的对象需要进行加法操作,就可以直接使用+运算符。例如Integer num1(3), num2(5); Integer result = num1 + num2;,这里num1 + num2就会调用重载的operator+函数,实现两个Integer对象内部value值的相加,从而方便地完成类似普通整数相加的操作。
        return value += itg.value; // 将当前对象的value成员与传入对象的value成员相加,并返回结果
    }
    friend ostream& operator<<(ostream& os,Integer& it){ // 声明一个友元函数,用于重载输出流运算符“<<”,当需要在控制台输出Integer类的对象时,无需编写复杂的输出代码,直接使用cout << integerObject;(integerObject为Integer类的对象)即可。比如在调试程序查看Integer对象的值,或者展示计算结果时,这种方式让输出操作更加简洁直观,就像输出普通的int类型变量一样。
        return os << it.value; // 将对象的value成员输出到输出流os中,并返回该输出流
    }
private: // 声明私有成员,只能在类内部访问
    int value; // 类的私有成员变量,用于存储整数值
};

int main() { // 主函数,程序的入口点
    Integer zero; // 创建一个Integer类的对象zero,调用默认构造函数,value初始化为0
    Integer one; // 创建一个Integer类的对象one,调用默认构造函数,value初始化为0
    one = zero + 1; // 这里会发生隐式类型转换,将1转换为Integer类型,然后调用重载的“+”运算符函数
                    // 计算zero.value + 1,并将结果赋值给one.value
    cout << "zero=" << zero << ", "; // 输出字符串"zero=",然后调用重载的“<<”运算符函数输出zero对象的value值,再输出字符串", "
    cout << "one=" << one << endl; // 输出字符串"one=",然后调用重载的“<<”运算符函数输出one对象的value值,再换行
    return 0; // 程序正常结束,返回0给操作系统
}

8.指针(指针类型与成员访问权限:基类指针只能访问基类声明的成员,即使指向派生类对象)

#include <iostream>         // 引入输入输出流头文件,用于输入输出操作(如 cout)
using namespace std;      // 使用标准命名空间,允许直接使用 cout、endl 等标识符

class CBase {             // 定义基类 CBase
protected:
    int n;                // 受保护成员变量 n
public:
    CBase(int i) : n(i) {}  // 构造函数,用参数 i 初始化成员 n
    void Print() {        // 成员函数 Print,输出基类的 n 值
        cout << "CBase:n= " << n << endl;
    }
};

class CDerived : public CBase {  // CDerived 类公有继承 CBase
public:
    int v;                    // 公有成员变量 v
    CDerived(int i) : CBase(i), v(2 * i) {}  // 构造函数,先调用基类构造函数,再初始化 v
    void Func() {}            // 成员函数 Func(无具体实现)
    void Print() {            // 重写基类的 Print 函数,输出派生类的 n 和 v
        cout << "CDerived:n= " << n << endl;
        cout << "CDerived:v= " << v << endl;
    }
};

int main() {
    CDerived objDerived(3);  // 创建派生类对象 objDerived,传入参数 3
    CBase objBase(5);        // 创建基类对象 objBase,传入参数 5
    CBase* pBase = &objDerived;  // ① 基类指针指向派生类对象,合法操作
    CDerived* pDerived;      // 声明派生类指针 pDerived
    pDerived = &objDerived;  // 派生类指针指向派生类对象
    cout << "使用派生类指针调用函数" << endl;
    pDerived->Print();       // ② 派生类指针调用自身成员函数 Print,合法
    cout << "使用基类指针调用函数" << endl;
    pBase = pDerived;        // ③ 基类指针指向派生类指针,合法
    pBase->Print();          // 调用基类指针指向对象的 Print 函数(实际调用派生类重写版本)
    pBase->Func();           // ④ 语法错误!CBase 类中没有 Func 成员函数,无法调用
    cout << "使用派生类指针调用函数" << endl;
    pDerived->Print();       // 派生类指针再次调用 Print 函数
    return 0;
}

9.友元函数,实现 < 运算符重载,操作的是 Integer 对象

#include <iostream>         // 引入输入输出流头文件,用于实现输入输出功能(如使用 cout 输出)
using namespace std;      // 使用标准命名空间,避免每次使用标准库功能时都写 std::

class Integer {           // 定义基类 Integer
public:
    Integer(): n(0) {}     // Integer 构造函数,初始化私有成员 n 为 0
    // 声明友元函数(重载 < 运算符),允许该函数访问类的私有成员
    friend bool operator<(const Integer &b1, const Integer &b2); 
private:
    int n;                // 私有成员变量 n
};

class PosInteger: public Integer {  // PosInteger 类公有继承 Integer
public:
    PosInteger(): n(0) {}  // PosInteger 构造函数,初始化自身私有成员 n 为 0
    void setN(int i) { n = i; }  // 设置自身私有成员 n 的值
private:
    int n;                // 自身私有成员变量 n
};

// 实现友元函数,重载 < 运算符
bool operator< (const Integer &b1, const Integer &b2) {
    return b1.n < b2.n;   // 比较两个 Integer 对象的私有成员 n
}

int main() {              // 程序入口函数
    PosInteger a1, a2;    // 创建 PosInteger 类对象 a1 和 a2
    a1.setN(5);           // 设置 a1 自身的私有成员 n 为 5
    a2.setN(10);          // 设置 a2 自身的私有成员 n 为 10
    // 比较 a1 和 a2:由于 operator< 操作的是基类 Integer 的成员 n(始终为 0),而非 PosInteger 自身的 n
    cout << (a1 < a2) << endl;  
    return 0;             // 程序正常结束,返回 0
}

10.

#include <iostream>
// 引入标准输入输出流库,用于使用 cin 和 cout 进行输入输出操作
#include <cmath>
// 引入数学库,使用其中的 max 和 min 函数

using namespace std;
// 使用标准命名空间,这样就可以直接使用标准库中的类和函数,而无需加 std:: 前缀

class CShape	//基类:图形类
{
protected:
    double perimeter;		//图形的周长,子类可访问
    // 定义一个受保护的成员变量 perimeter,用于存储图形的周长
public:
    CShape()
    {
    };
    // 基类的默认构造函数,目前为空,不做任何操作

    virtual ~CShape()
    {
    };
    // 基类的虚析构函数,使用 virtual 关键字是为了确保在通过基类指针删除派生类对象时,能正确调用派生类的析构函数

    virtual double CalPeri()
    {	return 0;
    };
    // 虚函数,用于计算图形的周长,基类中默认返回 0,派生类可以重写该函数实现具体计算

    virtual void setPeri(double peri){}; 
    // 虚函数,用于设置图形的周长,基类中为空,派生类可以重写该函数实现具体设置

    virtual void PrintInfo(){};
    // 虚函数,用于打印图形的信息,基类中为空,派生类可以重写该函数实现具体打印
};

class CRectangle : public CShape
{
    double length, width;
    // 定义矩形的长和宽

public:
    CRectangle(double l, double w)
    {
        length = max(l,w); 
        width = min(l,w);
    };
    // 带参数的构造函数,初始化矩形的长和宽,确保长大于等于宽

    CRectangle()
    {
        length = 0; 
        width = 0;
    };	
    // 默认构造函数,将长和宽初始化为 0

    ~CRectangle()
    {
    };
    // 析构函数,目前为空,不做任何操作

    virtual double CalPeri();
    // 声明虚函数,用于计算矩形的周长

    virtual void setPeri(double); 
    // 声明虚函数,用于设置矩形的周长

    virtual void PrintInfo();
    // 声明虚函数,用于打印矩形的信息
};

double CRectangle::CalPeri()
{
    //**********found**********
    return 2*(length+width);
}
// 实现计算矩形周长的函数,根据矩形周长公式 2×(长 + 宽) 计算并返回结果

void CRectangle::PrintInfo()
{	cout<<"\t长度 = "<<this->length<<", 宽度 = "<<this->width<< ", 周长 = "<<this->perimeter<<endl;
}
// 实现打印矩形信息的函数,使用 this 指针访问当前对象的成员变量,输出矩形的长、宽和周长

void CRectangle::setPeri(double peri) 
{
    //**********found**********
    perimeter=peri;
}
// 实现设置矩形周长的函数,将传入的参数赋值给成员变量 perimeter

CShape *pShapes[100];	//用来存放矩形,最多100个
// 定义一个基类指针数组,最多可以存储 100 个指向 CShape 类型对象的指针,实际用于存储 CRectangle 对象

int main()
{	int i, n;
    double temp1, temp2;
    CRectangle *pr; 
    // 定义循环变量 i 和矩形个数 n,临时变量 temp1 和 temp2 用于存储输入的长和宽,以及一个指向 CRectangle 对象的指针 pr

    cout<<"请输入矩形的个数:";
    cin>>n;
    // 提示用户输入矩形的个数,并将输入的值存储到变量 n 中

    if (n<=0) return 0;
    // 如果输入的矩形个数小于等于 0,程序直接结束

    cout<<"请分别输入各矩形的两条边的长度,以空格为分隔符,回车键结束:";
    for( i = 0; i < n; ++i )
    {
        cin>>temp1>>temp2;
        // 提示用户输入每个矩形的两条边的长度,并将输入的值存储到 temp1 和 temp2 中

        pr = new CRectangle(temp1, temp2);
        // 使用 new 运算符动态创建一个 CRectangle 对象,并将其地址赋值给指针 pr

        pr->setPeri(pr->CalPeri());
        // 调用 CRectangle 对象的 CalPeri 函数计算周长,并将结果通过 setPeri 函数设置到对象的 perimeter 成员变量中

        //**********found**********
        pShapes[i]=pr;		
    }
    // 将创建的 CRectangle 对象的指针存储到基类指针数组 pShapes 中

    cout<<"共有"<<n<<"个矩形,如下:"<<endl;
    for ( i = 0; i < n; ++i )
    {	cout<<"第"<<i+1<<"个矩形:"; 
        //**********found**********
        pShapes[i]->PrintInfo();
        // 通过基类指针调用 PrintInfo 函数,由于 PrintInfo 是虚函数,会根据实际指向的对象类型调用 CRectangle 类的 PrintInfo 函数

        delete pShapes[i];		//释放空间
        // 使用 delete 运算符释放动态分配的内存,防止内存泄漏
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值