学生信息处理程序
描述
实现一个学生信息处理程序,计算一个学生的四年平均成绩。
要求实现一个代表学生的类,并且类中所有成员变量都是私有的。
补充下列程序中的 Student 类以实现上述功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <cstdlib>
using namespace std;
class Student {
// 在此处补充你的代码
};
int main() {
Student student; // 定义类的对象
student.input(); // 输入数据
student.calculate(); // 计算平均成绩
student.output(); // 输出数据
}
|
输入
输入数据为一行,包括:
姓名,年龄,学号,第一学年平均成绩,第二学年平均成绩,第三学年平均成绩,第四学年平均成绩。
其中姓名为由字母和空格组成的字符串(输入保证姓名不超过20个字符,并且空格不会出现在字符串两端),年龄、学号和学年平均成绩均为非负整数。信息之间用逗号隔开。
1
|
Tom Hanks,18,7817,80,80,90,70
|
输出
输出一行数据,包括:
姓名,年龄,学号,四年平均成绩。
信息之间用逗号隔开。
提示
必须用类实现,其中所有成员变量都是私有的。
输出结果中,四年平均成绩不一定为整数。
Solution
观察原代码,可以看到Student类有input、calculate、output三个成员函数。
而根据题意,需要记录姓名(字符串形式)、年龄、学号、以及四个学年的平均成绩,它们都是Student类中的Private变量,即无法被除Student类外的代码访问。
这里笔者当时完成的时候使用字符数组进行编写,是因为cstring这个库中不存在string类,因此无法使用string类进行快速编写。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class Student {
private:
char c[25];
char x;
int age;
int n = 0;
int num;
int aver_1;
int aver_2;
int aver_3;
int aver_4;
double aver;
public:
void input() {
while (c[++n] = getchar()) {
if (c[n] == ',') {
n--;
break;
}
}
cin >> age >> x >> num >> x >> aver_1 >> x >> aver_2 >> x >> aver_3 >> x >> aver_4;
}
void calculate() { aver = (double)((aver_1 + aver_2 + aver_3 + aver_4) / 4.0); }
void output() {
for (int i = 1; i <= n; i++) {
cout << c[i];
}
cout << ',' << age << ',' << num << ',' << aver;
}
};
int main() {
Student student; // 定义类的对象
student.input(); // 输入数据
student.calculate(); // 计算平均成绩
student.output(); // 输出数据
}
|
Complex类的成员函数
描述
请根据输出补足Complex类的成员函数,不能加成员变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class Complex {
private:
double r,i;
public:
void Print() {
cout << r << "+" << i << "i" << endl;
}
// 在此处补充你的代码
};
int main() {
Complex a;
a = "3+4i"; a.Print();
a = "5+6i"; a.Print();
return 0;
}
|
输入
输出
Solution
可以观察到这里需要写出一个构造函数,使得字符数组或者string类被转为一个Complex类对象,来实现程序功能。
也许学到后面的你会问,为什么这里是实现构造函数而不是重载等号运算符?事实上,构造函数的原理就是,首先它发现右边不是Complex类对象,因此尝试将其隐式转换为一个Complex类对象,再创建一个默认的Complex复制构造函数进行调用,将成员变量一一复制。
于是,只需要将这个字符串拆开即可,笔者当时完成的时候仍是使用字符数组。
由于创建了转换构造函数,因此系统不会生成默认构造函数,从而Complex a这一句会报错,此时需要新建一个空的默认构造函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
class Complex {
private:
double r, i;
public:
void Print() { cout << r << "+" << i << "i" << endl; }
Complex() {}
Complex(char c[]) {
r = c[0] - '0';
i = c[2] - '0';
}
};
int main() {
Complex a;
a = "3+4i";
a.Print();
a = "5+6i";
a.Print();
return 0;
}
|
Apple
描述
根据以下输出完善程序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <iostream>
using namespace std;
class Apple {
// 在此处补充你的代码
static void PrintTotal() {
cout << nTotalNumber << endl;
}
};
int Apple::nTotalNumber = 0;
Apple Fun(const Apple & a) {
a.PrintTotal();
return a;
}
int main()
{
Apple * p = new Apple[4];
Fun(p[2]);
Apple p1,p2;
Apple::PrintTotal ();
delete [] p;
p1.PrintTotal ();
return 0;
}
|
输入
输出
Solution
先观察程序,程序中nTotalNumber必然是一个静态成员变量,它只有一个并且不属于任何类对象,同时PrintTotal函数作为静态成员函数,负责打印出这个变量。
再看主函数,首先创建了一个类型为Apple,4个变量的数组,指针p指向下标0,然后通过Fun函数打印出nTotalNumber的值,注意它这里是值返回,并且调用的是拷贝构造函数,再新建两个Apple类变量并打印出值,然后再删除一个Apple数组并打印出值。
根据样例很容易看出,逻辑应该是默认构造函数使nTotalNumber加一,然后析构函数使nTotalNumber减一,而Fun中由于返回值调用拷贝构造函数后作为临时变量被析构,因此nTotalNumber是减一的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include <iostream>
using namespace std;
class Apple {
public:
static int nTotalNumber;
Apple() { nTotalNumber++; }
~Apple() { nTotalNumber--; }
static void PrintTotal() { cout << nTotalNumber << endl; }
};
int Apple::nTotalNumber = 0;
Apple Fun(const Apple& a) {
a.PrintTotal();
return a;
}
int main() {
Apple* p = new Apple[4];
Fun(p[2]);
Apple p1, p2;
Apple::PrintTotal();
delete[] p;
p1.PrintTotal();
system("pause");
return 0;
}
// 调用系统自带的构造函数不会增加 但后续销毁临时变量会减少
|
返回什么才好呢
描述
根据以下输出完善程序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <iostream>
using namespace std;
class A {
public:
int val;
A(int
// 在此处补充你的代码
};
int main()
{
int m,n;
A a;
cout << a.val << endl;
while(cin >> m >> n) {
a.GetObj() = m;
cout << a.val << endl;
a.GetObj() = A(n);
cout << a.val<< endl;
}
return 0;
}
|
输入
多组数据,每组一行,是整数 $m$ 和 $n$ 。
输出
先输出一行:
1 2 3
然后对每组数据,输出两行,第一行是 $m$ ,第二行是 $n$ 。
思路
根据main函数可以看出,此处A类型变量a在被声明后其val成员变量就为123,因此其中的转换构造函数应该使用缺省变量,或者写完这个函数再自己声明新的默认构造函数。
随后,发现a的GetObj成员函数可以修改val成员变量的值,那么它必然返回的是一个A&型变量(因为前面实现了转换构造函数,因此可以做到a.GetObj()=m),但是不能是int&型变量,因为有a.GetObj()=A(n)这一行。
然后,就是GetObj返回对当前A对象的引用,这里需要用到this指针,可以认为它是指向当前对象的一个指针,因此需要返回*this对其解引用,从而拿到当前对象的引用,注意指针和引用很容易混淆。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <iostream>
using namespace std;
class A {
public:
int val;
A(int m = 123) { val = m; } // 这是构造函数
A& GetObj() { return *this; } // 注意这个引用号 生成的不是临时变量而是引用
};
int main() {
int m, n;
A a;
cout << a.val << endl;
while (cin >> m >> n) {
a.GetObj() = m;
cout << a.val << endl;
a.GetObj() = A(n);
cout << a.val << endl;
}
return 0;
}
|
Big&Base 封闭类问题
描述
根据以下输出完善程序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include <iostream>
#include <string>
using namespace std;
class Base {
public:
int k;
Base(int n):k(n) { }
};
class Big
{
public:
int v;
Base b;
// 在此处补充你的代码
};
int main()
{
int n;
while(cin >>n) {
Big a1(n);
Big a2 = a1;
cout << a1.v << "," << a1.b.k << endl;
cout << a2.v << "," << a2.b.k << endl;
}
}
|
输入
多组数据,每组一行,是一个整数。
输出
对每组数据,输出两行,每行把输入的整数打印两遍
Solution
这里注意到Big类有一个Base类成员对象,再看main函数,得知需要编写一个Big类转换构造函数,这个转换构造函数需要将成员变量v赋值,同时调用Base类的转换构造函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include <iostream>
#include <string>
using namespace std;
class Base {
public:
int k;
Base(int n) : k(n) {}
};
class Big {
public:
int v;
Base b;
Big(int n) : v(n), b(n) {} // 构造v和k
// 在此处补充你的代码
};
int main() {
int n;
while (cin >> n) {
Big a1(n);
Big a2 = a1;
cout << a1.v << "," << a1.b.k << endl;
cout << a2.v << "," << a2.b.k << endl;
}
}
|
奇怪的类复制
描述
根据以下输出完善程序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <iostream>
using namespace std;
class Sample {
public:
int v;
// 在此处补充你的代码
};
void PrintAndDouble(Sample o)
{
cout << o.v;
cout << endl;
}
int main()
{
Sample a(5);
Sample b = a;
PrintAndDouble(b);
Sample c = 20;
PrintAndDouble(c);
Sample d;
d = a;
cout << d.v;
return 0;
}
|
输入
输出
Solution
首先,这里需要实现一个转换构造函数。
随后,观察样例,发现好像不是一个转换构造函数就能实现的事情,因此考虑实现一个拷贝构造函数。
实现之后,发现b=a跟PrintAndDouble传入值时会调用一次拷贝构造函数,注意d=a不会调用,因为此时d已经由默认构造函数(此处由于声明了转换构造函数,需要自己声明)声明过了,因此只会调用默认的赋值运算符而已。
然后,根据给出的输出观察到默认构造函数的行为是将v置零,转换构造函数的行为是将x赋值给v,拷贝构造函数将x+2赋值给v。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
#include <iostream>
using namespace std;
class Sample {
public:
int v;
Sample() { v = 0; }
Sample(int x) : v(x) {}
Sample(const Sample& s) : v(s.v + 2) {}
// 在此处补充你的代码
};
void PrintAndDouble(Sample o) {
cout << o.v;
cout << endl;
}
int main() {
Sample a(5);
Sample b = a;
PrintAndDouble(b);
Sample c = 20;
PrintAndDouble(c);
Sample d;
d = a;
cout << d.v;
system("pause");
return 0;
}
|