第 2 节

C/C++公共基础练习题及答案

作者
董佳辉的头像董佳辉
协作者
房梓豪的头像房梓豪尚凡兴的头像尚凡兴
发布于 2025/02/07更新于 2026/08/20

一、程序题

C++的HelloWorld!

image\.png

#include <iostream>

using std::cout;
using std::endl;

int main()
{
    cout << "Hello,World!" << endl;
    return 0;
}

输入一个圆半径( r )当r>=0时,计算并输出圆的面积和周长,如果r<0输出input error字符串。(PI取3.14159)

image\.png

#include <iostream>
#include <stdlib.h>

#define PI (3.14159)

using std::cout;
using std::cin;
using std::endl;

int main()
{
    double r;

    cout << "请输入圆的半径:";
    cin >> r;

    if (r < 0)
    {
        cout << "input error" << "\n";
    }
    else {
        double area = PI * r * r;
        double perimeter = 2 * PI * r;

        cout << "圆的面积为:" << area << endl;
        cout << "圆的周长为:" << perimeter << endl;
    }

    system("pause");
    return 0;
}

输入10个整形数,并按从小到大输出这10个数。

image\.png

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

int main() {
    const int N = 10;
    int nums[N];

    cout << "请输入10个整数:" << endl;
    for (int i = 0; i < N; i++) {
        cin >> nums[i];
    }

    for (int i = 0; i < N - 1; i++) {
        for (int j = 0; j < N - i - 1; j++) {
            if (nums[j] > nums[j + 1]) {
                int temp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = temp;
            }
        }
    }
    cout << "从小到大排序后的结果为:" << endl;
    for (int i = 0; i < N; i++) {
        cout << nums[i] << " ";
    }
    cout << endl;

    return 0;
}

如果一个 3 位数等于其各位数字的立方和,则称这个数为水仙花数。

例如:153 = 1^3 + 5^3 + 3^3,因此 153 就是一个水仙花数 编写程序打印出所有的水仙花数

image\.png

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

int main()
{
    for (int i = 100; i < 1000; i++)
    {
        int digit1 = i / 100;
        int digit2 = (i / 10) % 10;
        int digit3 = i % 10;

        if (i == digit1 * digit1 * digit1 + digit2 * digit2 * digit2 + digit3 * digit3 * digit3)
        {
            cout << i << endl;
        }
    }

    return 0;
}

将Shandong University of Technology字符串实现逆序输出(用数组)

image\.png

#include <iostream>
#include <string>

using std::cout;
using std::cin;
using std::endl;

int main()
{
    char str[] = "Shandong University of Technology";

    int length = sizeof(str)/sizeof(str[0]);

    for (int i = length - 1; i >= 0; i--)
    {
        cout << str[i];
    }
    cout << endl;
    return 0;
}

定义一个返回值是float的函数,输入圆的半径,计算圆的面积。并在主函数内输出该函数计算出的面积。(用宏定义 pi = 3.14159)

image\.png

#include <iostream>

#define PI 3.14159

using std::cout;
using std::cin;
using std::endl;

float calculateArea(int radius);  //声明函数

int main()
{
    int radius;
    cout << "请输入圆的半径:";
    cin >> radius;

    auto area = calculateArea(radius);    //调用函数
    cout << "圆的面积为:" << area << endl;

    return 0;
}

float calculateArea(int radius)    //定义函数
{
    float Area = PI * radius * radius;
    return Area;
}

定义函数fun的功能是:根据输入的三个边长(整型值),判断能否构成三角形;构成的是等边三角形,还是等腰三角形。若能构成等边三角形函数返回3,若能构成等腰三角形函数返回2,若能构成三角形函数返回1,若不能构成三角形函数返回0。

并调用该函数实现判断三角形的功能:例如,输入的值为" 3 4 5 ",则输出为" 1 ",若输入的值为" 3 5 9 ",则输出的值为" 0 "。

image\.png

#include <iostream>

using namespace std;

int fun(int x,int y,int z);

int main()
{
    int x,y,z,shape;
    cout << "\n请输入x,y,z: " << endl;
    cin >> x >> y >> z;
    shape=fun(x,y,z);
    cout << "\n类型是:" << shape << endl;
    return 0;
}


int fun(int x,int y,int z)
{
    if(x+y>z&&y+z>x&&x+z>y)
    {
        if(x==y&&y==z)
            return 3;
        else if(x==y||y==z||x==z)
            return 2;
        else
            return 1;
    }
    else
        return 0;
}

输入n(奇数)个数,这n个数用scanf或者cin输入,要求输入的所有元素中, 其中只有一个数出现了奇数次,其他数都出现了偶数次,请找出这个数。(提示:位操作符)

image\.png

#include <iostream>

using namespace std;

int main()
{
 int n;
    cout << "请输入n的值:";
    cin >> n;

    int result = 0;
    for (int i = 0; i < n; i++) {
        int num;
        cout << "请输入第" << i+1 << "个数:";
        cin >> num;
        result ^= num;
    }

    cout << "出现奇数次的数是:" << result << endl;

    return 0;
}
与运算符(&)

与运算符对两个操作数的每一位执行逻辑与操作。只有当两个对应位都为1时,结果位才为1,否则为0。

或运算符(|)

或运算符对两个操作数的每一位执行逻辑或操作。只要有一个对应位为1,结果位就为1。

异或运算符(^)

异或运算符对两个操作数的每一位执行逻辑异或操作。当两个对应位不同,结果位为1;相同,结果位为0。

^运算符满足交换律和结合律。

取反运算符(~)

取反运算符对操作数的每一位执行逻辑取反操作。0变1,1变0。

左移运算符(<<)

左移运算符将操作数的所有位向左移动指定的位数,右边补0。左移n位相当于乘以2的n次方。

示例:

int a = 5; // 二进制: 0000 0101

int b = a << 1; // 左移1位,结果: 0000 1010,即10

右移运算符(>>)

右移运算符将操作数的所有位向右移动指定的位数。对于无符号数,左边补0;对于有符号数,补符号位(算术右移)或补0(逻辑右移)。

示例:

int a = 5; // 二进制: 0000 0101

int b = a >> 1; // 右移1位,结果: 0000 0010,即2

题目:使用C语言的头文件stdio.h中的scanf(如果编译器报错用scanf_s)和printf在.cpp文件中进行混合编程,需要输入一个浮点型数a,并打印该浮点型数并保留2位小数。

image1\.png

#include <stdio.h>
int main()
{
    float x;
    scanf_s("%f",&x);
    printf("%.2f",x);
    return 0;
}
//scanf_S是Microsoft在win中使用的一种更安全的输入函数,相比scanf 可以避免内存溢出的风险

题目:创建一个命名空间ns1,在该命名空间中有一个函数swap,他的作用是交换两个数的值,返回值是void。请调用这个函数,交换两个数的值。

image2\.png

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

namespace ns1
{
    void swap(int *a,int *b);
}

int main()
{
    int x , y;
    cout << "X:";
    cin >> x;
    cout << "Y:";
    cin >> y;
    ns1::swap(&x,&y);
    cout << "交换后:\nX=" << x << "\nY=" << y << endl;
    return 0;
}

void ns1::swap(int *a,int *b)
{
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

**题目:请使用联合体来完成输入一个字母,并打印他的ascii码。 **

image3\.png

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

union Convert
{
    int asc;
    char letter;
};

typedef Convert con;

con con__;  //有的编译器需要初始化后三个字节,所以需要用全局变量。

int main()
{
    cin >> con__.letter;
    cout << con__.asc << endl;
    return 0;
}

这里体现了联合体公用一块内存,以及小端存储的特性:

  1. 假如当cin输入一个字符c时,由于c的ascii码为99,其在内存中的顺序为:

99 00 00 00(十六进制格式)

当读取时,由于letter和asc共用一块内存,char占1字节,int占4字节,但是因为是小端存储,排在前面的是低地址位,所以读取出来的是0x000099,故输出的为99,即ascii码

  1. 假如是大端存储,那么读取出来的就是0x99000000,即1660944384

题目:编写一个自己的库(.cpp和.h) :请创建一个文件out_test.cpp,请在该文件中定义一个短整型变量a,并赋值5,在该文件中继续定义一个函数print_short(short int x),该函数的功能是打印一个短整型变量。请在主函数中调用out_test.cpp中的print_short函数并打印变量a。

image4\.png

主函数****main.cpp:

#include <iostream>
#include "out_test.h"

// using std::cout;
// using std::cin;
// using std::endl;

extern short int a;

int main()
{
    print_short(a);
    return 0;
}

out_test.cpp:

#include "out_test.h"

short int a = 5;
void print_short(short int x)
{
    std::cout << x << endl;
}

out_test.h:

#ifndef __OUT_TEST_H_   //条件编译,选写,建议以后学习用条件编译
#define __OUT_TEST_H_   //条件编译,选写,建议以后学习用条件编译

#include <iostream>

void print_short(short int x);


#endif   //条件编译,选写,建议以后学习用条件编译

**题目: 请创建一个结构体student_stru,其有2个成员变量name和math_score,一个存姓名,一个存数学分数,请在主函数中用****stu student1;**创建一个结构体变量student1(需要用typedef),然后name赋值李华,math_score赋值70。然后创建一个函数change_score,返回值为void,该函数的作用是把math_score改成80,把姓名改成李丽。然后在主函数先打印没调用该函数之前的结果,然后再调用该函数,并在主函数中打印调用函数后的name和math_score。

image5\.png

#include <iostream>
#include <string>

using std::cout;
using std::cin;
using std::endl;

typedef struct student_stru
{
    std::string name;
    float math_score;
}stu;                     //这里注意区分C&C++在结构体定义上的细微差别

void change_score(stu *ps);

int main()
{
    stu student1;
    student1.name = "李华";
    student1.math_score = 70;
    cout << "调用函数前:" << endl;
    cout << student1.name << "的数学成绩是" << student1.math_score << endl;
    change_score(&student1);
    cout << "调用函数后:" << endl;
    cout << student1.name << "的数学成绩是" << student1.math_score << endl;
    return 0;
}

void change_score(stu *ps)
{
    ps->name = "李丽";
    ps->math_score = 80;
}

在许多数据协议中,数据串都是以字节(uint8_t)为单位发送的。但是1个字节的数据只能存放8位二进制数据,有的数据需要16位甚至更多二进制才能存放,所以我们在传送一个数据的时候,通常要连续发送若干个字节,这若干个字节构成一个数据。 现在,我们需要处理我们接收到的数据串,一共有2个字节,该协议规定,第一个字节为数据的高8位(DH),第二个字节为数据的低8位(DL)。请创建一个函数 ' int16_t data_calc(uint8_t DH,uint8_t DL) ' ,该函数的作用是将这两个字节的数据串,进行数据处理,处理成一个有符号短整型(int16_t)的数据。DH我们规定是0x50,DL是0x2E。[tips: uint8_t就是unsigned char的别名,int16_t就是short int的别名,都是由typedef关键字起别名而来,C++头文件中自带该别名,可以直接使用]

image\.png

#include <iostream>
#include <ios>   //hex和dec是该头文件下的std命名空间中的

using std::cout;
using std::cin;
using std::endl;

/*  常用的别名(部分C++自带,不用咱们写)
typedef unsigned char byte;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef float fp32;
typedef double fp64;
*/

int16_t data_calc(uint8_t DH,uint8_t DL);

int main()
{
    uint8_t DH = 0x50,DL = 0x2E;
    cout << "高8位DH:";
    cout << std::hex << "0x" << (int)DH << endl;
    cout << "低8位DL:";
    cout << std::hex << "0x" << (int)DL << endl;   //此行的hex可以不写
    auto DATA = data_calc(DH,DL);
    cout << "经数据处理后的结果是:" << std::dec << DATA << "\n";

    return 0;
}

int16_t data_calc(uint8_t Data_H,uint8_t Data_L)
{
    int16_t Data = (int16_t)((int16_t)Data_H << 8 | Data_L);
    return Data;
}

C++函数重载:定义3个的函数print,一个print用来打印整形,第二个用来打印双精度浮点数,第三个用来打印字符串。

image\.png

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

/*  常用的别名(部分C++自带,不用咱们写)
typedef unsigned char byte;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef float fp32;
typedef double fp64;
*/

void print(int i);
void print(double f);
void print(char c[]);

int main()
{
    int x;
    double y;
    char z[50];
    cout << "请输入整形X:";
    cin >> x;
    cout << "请输入双精度浮点形Y:";
    cin >> y;
    cout << "请输入字符串Z:";
    cin >> z;

    cout << "以下是调用print函数打印的结果:" << endl;
    print(x);
    print(y);
    print(z);

    return 0;
}

void print(int i)
{
    cout << "整数为: " << i << endl;
}

void print(double f)
{
    cout << "双精度浮点数为: " << f << endl;
}

void print(char c[])
{
    cout << "字符串为: " << c << endl;
}

函数模板:定义1个的函数模板print,使该函数模板完成上一题的要求。

image\.png

#include <iostream>
#include <ios>

using std::cout;
using std::cin;
using std::endl;

/*  常用的别名(部分C++自带,不用咱们写)
typedef unsigned char byte;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef float fp32;
typedef double fp64;
*/

template<typename T>

void print(T a)
{
    cout << a << endl;
}

int main()
{
    int x;
    double y;
    char z[50];
    cout << "请输入整形X:";
    cin >> x;
    cout << "请输入双精度浮点形Y:";
    cin >> y;
    cout << "请输入字符串z:";
    cin >> z;

    cout << "以下是调用print函数打印的结果:" << endl;

    cout << "整数为: ";
    print(x);   //第一种调用方式:不指定T的类型,由编译器自己推导出来T是int
    cout << "双精度浮点数为: ";
    print<double>(y);      //第二种调用方式:指定类型的调用方式
    cout << "字符串为: ";
    print<char *>(z);      //这个地方一定是 char* 类型的

    return 0;
}

内存管理:请用不定长数组,完成以下要求:输入已知数量的若干的整数,并打印出其相加后的结果。

image\.png

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

/*  常用的别名(部分C++自带,不用咱们写)
typedef unsigned char byte;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef float fp32;
typedef double fp64;
*/

int main()
{
    int n;
    int sum = 0;
    cout << "输入数组元素数量n:";
    cin >> n;
    int *arr = new int[n];
    for(int i = 0;i < n;i++)
    {
        cout << "请输入第" << i+1 << "个数的值:";
        cin >> arr[i];
        sum += arr[i];
    }
    cout << "结果是:" << sum << endl;
    delete []arr;
    return 0;
}

智能指针**:创建一个结构体stu,内有成员name和math_score,一个存放名字,一个存放数学成绩。请使用智能指针创建一个结构体指针变量pstudent,并使用指针给该结构体变量中的成员变量赋值,并打印出来。**

image6\.png

#include <iostream>
#include <memory>
#include <string>

using std::cout;
using std::cin;
using std::endl;

struct stu
{
    std::string name;
    float math_score;
};

int main()
{
    auto pstudent = std::make_shared<stu>();
    (*pstudent).name = "小明";   //第一种调用方法
    pstudent->math_score = 90;  //第二种调用方法
    cout << pstudent->name << "的数学分数为" << pstudent->math_score << endl;
    return 0;
}

class(类):请创建一个class circle(圆类),该类通过构造函数传入双精度浮点数类型的半径参数,有两个公开(public)的方法,分别是print_circumference()和print_area(),第一个方法用来打印圆的周长,第二个方法用来打印圆的面积,该类还有析构函数用来打印字符串“析构函数运行完毕!”。请使用该类计算一个圆的周长和面积,并打印。(圆周率取3.1415926)

image\.png

#include <iostream>

#define pi (3.1415926)

using std::cout;
using std::cin;
using std::endl;

/*  常用的别名(部分C++自带,不用咱们写)
typedef unsigned char byte;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef float fp32;
typedef double fp64;
*/
class circle
{
    public:
        circle(double r);
        ~circle(void);
        void print_circumference();
        void print_area();
    private:
        double radius;
};

int main()
{
    double r1;
    cout << "请输入圆的半径r:";
    cin >> r1;
    circle cir1(r1);
    cir1.print_circumference();
    cir1.print_area();
    return 0;
}

circle::circle(double r)
{
    this->radius = r;
}

circle::~circle(void)
{
    cout << "析构函数运行完毕!" << endl;
}

void circle::print_circumference()
{
    double circumference = 2 * this->radius * pi;
    cout << "圆的周长是:" << circumference << endl;
}

void circle::print_area()
{
    double area = this->radius * this->radius * pi;
    cout << "圆的面积是:" << area << endl;
}

智能指针:请用shared_ptr创建一个上一题的类对象指针,并使用指针来完成上一题的要求。

image\.png

#include <iostream>
#include <memory>

#define pi (3.1415926)

using std::cout;
using std::cin;
using std::endl;

/*  常用的别名(部分C++自带,不用咱们写)
typedef unsigned char byte;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef float fp32;
typedef double fp64;
*/

class circle
{
    public:
        circle(double r);
        ~circle(void);
        void print_circumference();
        void print_area();
    private:
        double radius;
};

int main()
{
    double r1;
    cout << "请输入圆的半径r:";
    cin >> r1;
    auto cir1_ptr = std::make_shared<class circle>(r1);
    cir1_ptr->print_circumference();
    cir1_ptr->print_area();
    return 0;
}

circle::circle(double r)
{
    this->radius = r;
}

circle::~circle(void)
{
    cout << "析构函数运行完毕!" << endl;
}

void circle::print_circumference()
{
    double circumference = 2 * this->radius * pi;
    cout << "圆的周长是:" << circumference << endl;
}

void circle::print_area()
{
    double area = this->radius * this->radius * pi;
    cout << "圆的面积是:" << area << endl;
}

混合编译

写一个C语言的工程,但是要求调用C++的库。

主函数写在main.c文件中,然后新建两个C++的库,分别是main_inherit.cpp、main_inherit.h和test_lib.cpp,test_lib.h。

test_lib库用来定义一个命名空间叫ns_demo,该命名空间里有一个swap函数,返回值是void,用来交换两个整形的值。

main_inherit库里定义一个main_mix_com函数,该函数会被main函数调用,该函数的作用是输入X,Y的值,并调用test_lib库里的swap函数进行交换X,Y的值,最后打印X,Y的值。

main.c中用来调用main_mix_com函数。

image\.png

main.c(注意这里是.c不是.cpp)

#include <stdio.h>
#include "main_inherit.h"

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

main_inherit.cpp

#include "main_inherit.h"
#include "test_lib.h"

#include <iostream>

void main_mix_com(void)
{
        int a;
        int b;
        std::cout << "请输入a:" << std::endl;
        std::cin >> a;
        std::cout << "请输入b:" << std::endl;
        std::cin >> b;
        ns_demo::swap(&a, &b);
        std::cout << "交换后a的值:" << a << std::endl;
        std::cout << "交换后b的值:" << b << std::endl;
}

main_inherit.h

#ifndef __MAIN_INHERIT_H_    //头文件防止引用重复的条件编译
#define __MAIN_INHERIT_H_   //头文件防止引用重复的条件编译

#ifdef __cplusplus    //混合编译的条件编译
extern "C"           //混合编译的条件编译
{                  //混合编译的条件编译
#endif             //混合编译的条件编译
/*  头文件内容开始   */

//头文件内容:预处理、函数声明、变量声明
        void main_mix_com(void);


/*   头文件内容结束  */
#ifdef __cplusplus     //混合编译的条件编译
}                      //混合编译的条件编译
#endif                 //混合编译的条件编译

#endif   //头文件防止引用重复的条件编译

test_lib.cpp

#include "test_lib.h"
void ns_demo::swap(int* a, int* b)
{
        int temp = *a;
        *a = *b;
        *b = temp;
}

test_lib.h

#ifndef __TEST_LIB_H_    //头文件防止引用重复的条件编译
#define __TEST_LIB_H_   //头文件防止引用重复的条件编译

#ifdef __cplusplus    //混合编译的条件编译
extern "C"           //混合编译的条件编译
{                   //混合编译的条件编译
#endif             //混合编译的条件编译
/*  头文件内容开始   */

//头文件内容:预处理、函数声明、变量声明
namespace ns_demo
{
   void swap(int* a, int* b);
}

/*   头文件内容结束  */
#ifdef __cplusplus     //混合编译的条件编译
}                      //混合编译的条件编译
#endif                 //混合编译的条件编译

#endif   //头文件防止引用重复的条件编译

中间部分涉及到C/C++的混合编译的问题

使用混合编译用于确保代码可以在C和C++环境下正确编译。C++编译器会将函数名进行“名称修饰”(name mangling),而C编译器不会。为了在C++中调用C函数,需要使用 extern "C" 来防止名称修饰。

友元函数

请创建一个class circle(圆类),该类通过构造函数传入双精度浮点数类型的半径参数,有一个公开(public)的方法,是print_circumference(),有三个私有(private)的变量,分别是radius(半径),cirumference(周长)和area(面积),通过该类里的方法用来计算圆的周长并把结果存放到circumference中,然后并打印circumference的值,该类还有析构函数用来打印字符串“析构函数运行完毕!”。然后新建一个外部函数print_area(),使该函数是该类的友元函数,通过该函数可以计算圆的面积,并把结果存放到上面类中的area变量中,并打印area变量。

请创建一个类对象,然后打印周长和面积。

image\.png

#include <iostream>

#define pi (3.1415926)

using std::cout;
using std::cin;
using std::endl;

/*  常用的别名(部分C++自带,不用咱们写)
typedef unsigned char byte;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef float fp32;
typedef double fp64;
*/

class circle
{
    public:
        circle(double r);
        ~circle(void);
        void print_circumference();
        friend void print_area(circle *p_cir);
    private:
        double radius;
        double circumference;
        double area;
};


int main()
{
    double r1;
    cout << "请输入圆的半径r:";
    cin >> r1;
    circle cir1(r1);
    cir1.print_circumference();
    print_area(&cir1);
    return 0;
}

circle::circle(double r)
{
    this->radius = r;
}

circle::~circle(void)
{
    cout << "析构函数运行完毕!" << endl;
}

void circle::print_circumference()
{
    this->circumference = 2 * this->radius * pi;
    cout << "圆的周长是:" << this->circumference << endl;
}

void print_area(circle *p_cir)
{
    p_cir->area = p_cir->radius * p_cir->radius * pi;
    cout << "圆的面积是:" << p_cir->area << endl;
}

友元类

请创建一个class circle(圆类),该类通过构造函数传入双精度浮点数类型的半径参数,有两个公开(public)的方法,分别是calc_circumference()和calc_area(); 有三个私有(private)的变量,分别是radius(半径),cirumference(周长)和area(面积)。第一个方法用来计算圆的周长并把结果存放到circumference中,不打印circumference的值,第二个方法用来可以计算圆的面积,并把结果存放到上面类中的area变量中,不打印area变量。该类还有析构函数用来打印字符串“析构函数运行完毕!”。

请再创建第二个类class big_circle(大圆类),该类是circle的友元类,里面有1个方法,用来打印circle类中circumference和area变量。

image\.png

#include <iostream>

#define pi (3.1415926)

using std::cout;
using std::cin;
using std::endl;


/*  常用的别名(部分C++自带,不用咱们写)
typedef unsigned char byte;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef float fp32;
typedef double fp64;
*/

class circle
{
    public:
        circle(double r);
        ~circle(void);
        void calc_circumference();
        void calc_area();
        friend class big_circle;
    private:
        double radius;
        double circumference;
        double area;
};

class big_circle
{
    public:
        void print(circle cir);
};

int main()
{
    double r1;
    cout << "请输入圆的半径r:";
    cin >> r1;
    circle cir1(r1);
    big_circle big_cir1;
    cir1.calc_circumference();
    cir1.calc_area();
    big_cir1.print(cir1);
    return 0;
}

circle::circle(double r)
{
    this->radius = r;
}

circle::~circle(void)
{
    cout << "析构函数运行完毕!" << endl;
}

void circle::calc_circumference()
{
    this->circumference = 2 * this->radius * pi;
}

void circle::calc_area()
{
    this->area = this->radius * this->radius * pi;
}

void big_circle::print(circle cir)
{
    cout << "圆的周长是:" << cir.circumference << endl;
    cout << "圆的面积是:" << cir.area << endl;
}

运算符重载

请创建一个class circle(圆类),该类通过构造函数传入双精度浮点数类型的半径参数,有两个公开(public)的方法,分别是calc_circumference()和calc_area(); 有三个***公开(public)***的变量,分别是radius(半径),cirumference(周长)和area(面积)。第一个方法用来计算圆的周长并把结果存放到circumference中,并打印circumference的值,第二个方法用来可以计算圆的面积,并把结果存放到上面类中的area变量中,并打印area变量。该类还有析构函数用来打印字符串“析构函数运行完毕!”。

请先创建3个circle对象,cir1,cir2,cir3,并重载加法运算符,使两个类中的面积和周长都分别想加,并储存在第三个类中对应的变量中。然后在主函数中输出第三个类中的周长和面积(也用输出cout重载)。

image\.png

#include <iostream>

#define pi (3.1415926)

using std::cout;
using std::cin;
using std::endl;

/*  常用的别名(部分C++自带,不用咱们写)
typedef unsigned char byte;
typedef unsigned char uint8_t;
typedef short int int16_t;
typedef float fp32;
typedef double fp64;
*/


class circle
{
    public:
        circle(double r);
        ~circle(void);
        void calc_circumference();
        void calc_area();

        circle operator+(circle &cir)
        {
            circle sumcir(0);
            sumcir.circumference = this->circumference + cir.circumference;
            sumcir.area = this->area + cir.area;
            return sumcir;
        }

        double radius;
        double circumference;
        double area;
};



std::ostream & operator<<(std::ostream &output,circle &cir)
{
    output << "周长:" << cir.circumference << endl << "面积:" << cir.area;
    return output;
}


int main()
{
    double r1,r2,r3;
    cout << "请输入第一个圆的半径r1:";
    cin >> r1;
    cout << "请输入第一个圆的半径r2:";
    cin >> r2;
    r3 = 0;
    circle cir1(r1);
    circle cir2(r2);
    circle cir3(r3);
    cir1.calc_circumference();
    cir1.calc_area();
    cir2.calc_circumference();
    cir2.calc_area();
    cir3 = cir1 + cir2;
    cout << cir3 << endl;
    return 0;
}

circle::circle(double r)
{
    this->radius = r;
}

circle::~circle(void)
{
    cout << "析构函数运行完毕!" << endl;
}

void circle::calc_circumference()
{
    this->circumference = 2 * this->radius * pi;
}

void circle::calc_area()
{
    this->area = this->radius * this->radius * pi;
}

继承1

创建一个父类(基类) class shape,该类中有两个公开方法分别是setwidth(int w)和setheight(int h),还有两个受保护的变量,width和height。这两个方法的作用是将这两个函数的入口参数w赋值给width,h赋值给height。

再创建一个衍生类class Rectangle,该类继承父类class Shape,该类中有一个公开的方法print_area是用来计算宽乘高,并打印面积的。

请创建一个class Rectangle对象,并输入宽和高,并打印面积。

image\.png

#include <iostream>

using namespace std;

// 基类
class Shape
{
   public:
      void setWidth(int w)
      {
         width = w;
      }
      void setHeight(int h)
      {
         height = h;
      }
   protected:
      int width;
      int height;
};

// 派生类
class Rectangle: public Shape
{
   public:
      int getArea()
      {
         return (width * height);
      }
};

int main(void)
{
   Rectangle Rect;

    int width, height;

    cout << "输入Width:";
    cin >> width;
    cout << "输入Height:";
    cin >> height;

    Rect.setWidth(width);
    Rect.setHeight(height);

   // 输出对象的面积
   cout << "Total area: " << Rect.getArea() << endl;

   return 0;
}

继承2

创建一个父类(基类) class shape,该类的构造函数有参,负责给width和height传值。其中有1个公开方法是getarea(),还有三个受保护的变量,width,height,area。方法getarea是用来输出area的值

再创建一个衍生类class Rectangle,该类继承父类class Shape,也拥有构造函数,负责给父类构造函数传参,该类中有一个公开的方法getarea是用来计算矩形,宽乘高,但是不打印面积的。

请再创建一个衍生类class Triangle,该类继承父类class Shape,有构造函数,负责直接给width和height变量传参,该类中有一个公开的方法getarea,用来计算三角形的面积,不打印。

请在主函数中在堆区创建两个对象,一个是rectangle类对象,一个是triangle类对象,分别输入宽和高,并分别输出面积。

image\.png

#include <iostream>
#include <memory>

using namespace std;

// 基类
class Shape
{
public:
    Shape(int w, int h)
    {
        width = w;
        height = h;
    }
    void getarea()
    {
        cout << "面积是:" << area << endl;
    }
protected:
    int width;
    int height;
    int area;
};

// 派生类
class Rectangle : public Shape
{
public:
    Rectangle(int w,int h) : Shape(w,h)
    {

    }
    void getarea()
    {
        area = (width * height);
    }
};

class Triangle : public Shape
{
    public:
        Triangle(int w,int h) : Shape(w,h)
        {

        }
        void getarea()
        {
            area = (width * height / 2);
        }
};


int main(void)
{
    int width, height;
    cout << "输入Width:";
    cin >> width;
    cout << "输入Height:";
    cin >> height;

//    Rectangle a(width, height);
    Rectangle* p_Rect = new Rectangle(width, height);   //两种在堆区开内存的方法
    auto p_Tria = std::make_shared<Triangle>(width, height);   //更推荐这种

    // 计算对象面积
    p_Rect->getarea();
    p_Tria->getarea();

    // 输出对象的面积
    p_Rect->Shape::getarea();
    p_Tria->Shape::getarea();

    delete p_Rect;  //注意第一种方式要释放内存
    return 0;
}

多态

(禁止使用智能指针)创建一个基类class Person,该类有构造函数,功能为打印“基类构造函数运行调用”,有一个公开的整形指针变量per_,该变量指向堆区整形地址。还有析构函数,功能为打印“基类析构函数调用”并打印per_的值,并最后释放per_。

然后创建一个派生类class Student,该类有构造函数,功能为打印“派生类构造函数运行调用”,有一个公开的整形指针变量stu_,该变量指向堆区整形地址。还有析构函数,功能为打印“派生类析构函数调用”并打印stu_的值,并最后释放stu_。

请用Person *ptr = new Student在堆区创建一个对象。然后并释放堆区内存,不要有任何内存泄露。

image\.png

#include <iostream>
using namespace std;
class Person {
public:
    Person()
    {
        cout << "基类构造函数调用!" << endl;
    }
    virtual ~Person()
    {
        cout << "基类析构函数: " << per_ << endl;
        delete per_;
    }
    int* per_ = new int;
};


class Student :public Person {
public:
    Student()
    {
        cout << "派生类构造函数调用!" << endl;
    }
    ~Student()
    {
        cout << "派生类析构函数: " << stu_ << endl;
        delete stu_;
    }
    int* stu_ = new int;
};



int main()
{
    Person* ptr = new Student;
    delete ptr;
    return 0;
}

类模板

创建一个MyArray类模板,该模板的功能是在堆区创建一个不定长数组,通过构造函数规定数组的长度,通过析构函数释放数组的内存。有两个私有变量,arr和index,分别表示数组0号元素的地址和数组元素的序号。还应有两个方法,一个方法用来给对应序号的数组元素赋值,另一个方法用来取出对应序号数组元素的值。

请在主函数中用智能指针创建一个该类模板,来创建一个int16_t的不定长数组,并给序号为0的数组元素赋值 并 打印序号为0的数组元素的值。

image\.png

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

template <class T>
class MyArray {
    private:
        T* arr;
        int size;
    public:
        MyArray(int size) {
            this->size = size;
            arr = new T[size];
        }
        ~MyArray() {
            delete []arr;
        }
        void set(int index, T value) {
            arr[index] = value;
        }
        T get(int index) {
            return arr[index];
        }
};


int main()
{
    int N;
    cout << "请输入数组的长度N:";
    cin >> N;
    auto parr = std::make_shared<MyArray<int16_t>>(N);
    int arr_index;
    cout << "请输入要赋值的元素的序号:";
    cin >> arr_index;
    int16_t arr_value;
    cout << "请输入对应的值:";
    cin >> arr_value;
    parr->set(arr_index,arr_value);
    cout << "请输入要获取的数组元素的序号:";
    cin >>arr_index;
    auto temp = parr->get(arr_index);
    cout << "0号元素的值是:" << temp << endl;
    return 0;
}

综合

①请定义一个叫stru_lib的库(stru_lib.cpp和stru_lib.h)。

②stru_lib库内有一个命名空间叫ns_demo。

③ns_demo命名空间中使用typedef声明定义了一个结构体类型别名叫stu。stu该结构体成员变量有name(学生姓名),age年龄,gpa(平均学分绩点)。

④ns_demo命名空间中还有两个函数分别是scan_student_info和print_student_info。

scan_student_info函数的返回值为void,用于给stu类型的结构体变量的所有成员变量赋值。

print_student_info函数用于打印stu类型的结构体变量的所有成员变量。

⑤请在main.cpp的主函数中在堆区创建n个stu类型的结构体变量(n由键盘输入),然后给这n个stu类型的变量都赋值,并打印。

image\.png

main.cpp

#include <iostream>
#include "stru_lib.h"
using std::cout;
using std::cin;
using std::endl;

int main()
{
    int n;
    cout << "请输入一共有多少个学生信息,n = ";
    cin >> n;
    //在堆区开辟n个不定长结构体数组
    ns_demo::stu* student_arr = new ns_demo::stu[n];
    //在栈区开辟5个结构体数组
    //ns_demo::stu students[5];
    for (int i = 0; i < n; i++)
    {
        cout << "请输入第" << i + 1 << "个学生的信息:";
        ns_demo::scan_student_info(&student_arr[i]);
        //&student_arr[i]等同于(student_arr + i)
    }
    for (int i = 0; i < n; i++)
    {
        cout << "当前输出第" << i + 1 << "个学生的信息:\n";
        ns_demo::print_student_info(student_arr + i);
        //student_arr + i等同于&student_arr[i]
    }
    delete []student_arr;
    return 0;
}

stru_lib.cpp

#include "stru_lib.h"

using std::cout;
using std::cin;
using std::endl;

void ns_demo::scan_student_info(stu* ps)
{
        cout << "请输入该同学的名字:";
        cin >> ps->name;
        cout << "请输入该同学的年龄:";
        cin >> ps->age;
        cout << "请输入该同学的平均学分绩点:";
        cin >> ps->gpa;
}
void ns_demo::print_student_info(stu* ps)
{
        cout << "该同学的名字为:" << ps->name << endl;
        cout << "该同学的年龄为:" << ps->age << endl;
        cout << "该同学的平均学分绩点为:" << ps->gpa << endl;
}

stru_lib.h

#ifndef __STRU_LIB_H_
#define __STRU_LIB_H_

#include <iostream>
#include <string>

namespace ns_demo
{
        typedef struct
        {
                std::string name;
                short age;
                float gpa;
        }stu;

        void scan_student_info(stu* ps);
        void print_student_info(stu* ps);
}

#endif

现代C++之基础

要求:

  • 定义基类 BaseCalculator,成员函数:

void do_calculation(int x, int y);
  • 这个函数里面会调用一个储存在该类里的私有的回调函数(std::function<int(int,int)>),并打印回调结果。

  • 该类里的所有成员函数不准直接出现两个数据相加的功能。

  • 该基类里可能不止一个成员函数,这算是一个提示。

  • 里面所有的打印请使用现代C++里的std::print或者std::println。

  • 如果编译器支持标准库模块化的话,可以选择使用modules。(标准库模块化在C++26将全面支持,而在C++20,C++23中仅MSVC编译器支持比较好)

  • 定义派生类 AddCalculator,继承 BaseCalculator,在这个类里实现能让两个数据相加的功能。

  • main() 里,创建 AddCalculator 对象,调用基类的 do_calculation(10, 20),打印结果。

这题至少两种写法,尽量可以写出2种写法。

image\.png

方法一:采用bind

import std.io;       // 代替 #include <iostream>
import std.functional; // 代替 #include <functional>
import std.print;    // 代替 #include <print>

class BaseCalculator
{
public:
    // 绑定回调函数
    void set_callback(std::function<int(int,int)> cb)
    {
        callback_ = std::move(cb);
    }

    // 调用回调并打印结果
    void do_calculation(int x, int y)
    {
        if(callback_)
        {
            int result = callback_(x, y);
            std::println("Calculation result: {}", result);
        }
    }

private:
    std::function<int(int,int)> callback_;
};

class AddCalculator : public BaseCalculator
{
public:
    AddCalculator()
    {
        // 绑定成员函数 add,传入 this
        set_callback(std::bind(&AddCalculator::add, this, std::placeholders::_1, std::placeholders::_2));
    }

    int add(int a, int b)
    {
        return a + b;
    }
};

int main()
{
    AddCalculator calc;

    calc.do_calculation(10, 20);  // 输出 Calculation result: 30

    std::println("Press Enter to continue...");
    std::cin.get();
    return 0;
}

image\.png

方法二:采用lambda表达式

import std.io;       // 代替 #include <iostream>
import std.functional; // 代替 #include <functional>
import std.print;    // 代替 #include <print>

class BaseCalculator
{
public:
    void set_callback(std::function<int(int,int)> cb)
    {
        callback_ = std::move(cb);
    }

    void do_calculation(int x, int y)
    {
        if(callback_)
        {
            int result = callback_(x, y);
            std::println("Calculation result: {}", result);  // 自动换行
        }
    }

private:
    std::function<int(int,int)> callback_;
};

class AddCalculator : public BaseCalculator
{
public:
    AddCalculator()
    {
        // 用lambda捕获this
        set_callback([this](int a, int b)
        {
            return a + b;
        });
    }
};

int main()
{
    AddCalculator calc;

    calc.do_calculation(10, 20);  // 输出 Calculation result: 30

    std::println("Press Enter to continue...");  // 自动换行
    std::cin.get();
    return 0;
}

image\.png