T1
定义一个分数类如下,要求实现分数的初始化与设置、四则运算及约分以及输出等功能,并在主函数中测试。
CPPclass Rational { private: int m; // 分母 int n; // 分子 void simple(); //约分 public: Rational(int nn = 1, int mm = 1); //构造 bool setM(int); // 设置分母,注意不能为零 void setN(int); //设置分子 Rational R_add(const Rational& A); //加法操作, 返回和对象 Rational R_mul(Rational& A); //乘法操作,返回乘积对象 void print(); //以分数形式显示,注意约分和符号 };
简单的模拟,没什么需要注意的:
CPP
#include <iostream>
using namespace std;
class Rational {
private:
int m; // 分母
int n; // 分子
void simple(); //约分
public:
Rational(int nn = 1, int mm = 1); //构造
bool setM(int); // 设置分母,注意不能为零
void setN(int); //设置分子
Rational R_add(const Rational& A); //加法操作, 返回和对象
Rational R_mul(Rational& A); //乘法操作,返回乘积对象
void print(); //以分数形式显示,注意约分和符号
};
Rational::Rational(int nn, int mm) {
n = nn;
m = mm;
if (m == 0)
m = 1; // 分母不能为0
simple();
}
void Rational::simple() {
if (n == 0) {
m = 1;
return;
}
if (m < 0) {
n = -n;
m = -m;
}
int a = abs(n), b = abs(m);
while (b != 0) {
int temp = a % b;
a = b;
b = temp;
}
n /= a;
m /= a;
}
bool Rational::setM(int newM) {
if (newM == 0)
return false;
m = newM;
simple();
return true;
}
void Rational::setN(int newN) {
n = newN;
simple();
}
Rational Rational::R_add(const Rational& A) {
return Rational(n * A.m + A.n * m, m * A.m);
}
Rational Rational::R_mul(Rational& A) {
return Rational(n * A.n, m * A.m);
}
void Rational::print() {
if (n == 0) {
cout << "0";
} else if (m == 1) {
cout << n;
} else if (m == -1) {
cout << -n;
} else {
cout << n << "/" << m;
}
}
int main() {
Rational r1(2, 3); // 2/3
Rational r2(1, 4); // 1/4
Rational sum = r1.R_add(r2); // 11/12
Rational prod = r1.R_mul(r2); // 1/6
cout << "r1 = ";
r1.print();
cout << endl;
cout << "r2 = ";
r2.print();
cout << endl;
cout << "r1 + r2 = ";
sum.print();
cout << endl;
cout << "r1 * r2 = ";
prod.print();
cout << endl;
return 0;
}
运行结果:
BASH
root@lsj-nas2:/vol2/1000/c程/信息技术实践# cd "/vol2/1000/c程/信息技术实践/" && g++ 2-1.cpp -o 2-1 && "/vol2/1000/c程/信息技术实践/"2-1
r1 = 2/3
r2 = 1/4
r1 + r2 = 11/12
r1 * r2 = 1/6
此外,AI给出了一种基于初始化列表的初始化方式:
CPP
Rational::Rational(int nn, int mm) : n(nn), m(mm) {
if (m == 0) m = 1; // 分母不能为0
simple();
}
经过查询,这是C++11引入的新型初始化方法,它支持:
防止隐式转换:传统的圆括号初始化允许发生可能丢失数据的转换,而列表初始化会阻止这种窄化转换。
数组和容器初始化:提供简洁的语法来初始化容器和数组。
结构体和类的初始化:提供统一的语法来初始化对象的成员变量。
T2
定义如下字符串类, 实现C++字符串的存储和操作。
CPPclass myString { public: myString(char* pn = 0); ~myString(); void set(const char* pn); // 将字符串设置为pn指向的内容,注意避免越界 void set(const myString& rStr); // 将字符串设置为rStr中的内容,注意避免越界 void print() const; // 输出字符串整体和长度 char get(int i) const; // 返回字符串中的下标为i的字符,注意i 的有效性 void toUpper(); //转化为大写字符串 bool strcompare(const myString& s); //比较字符串 private: char* pStr; // 指向存储字符串的空间 new char[size+1] int size; //包含字符的数目 };
简单的字符串模拟,注意空间的回收和空指针的处理:
CPP
#include <cctype>
#include <cstring>
#include <iostream>
using namespace std;
class myString {
public:
myString(char* pn = 0);
~myString();
void set(const char* pn); // 将字符串设置为pn指向的内容,注意避免越界
void set(const myString& rStr); // 将字符串设置为rStr中的内容,注意避免越界
void print() const; // 输出字符串整体和长度
char get(int i) const; // 返回字符串中的下标为i的字符,注意i 的有效性
void toUpper(); //转化为大写字符串
bool strcompare(const myString& s); //比较字符串
private:
char* pStr; // 指向存储字符串的空间 new char[size+1]
int size; //包含字符的数目
};
myString::myString(char* pn) {
if (pn == 0) {
size = 0;
pStr = new char[1];
pStr[0] = '\0';
} else {
size = strlen(pn);
pStr = new char[size + 1];
strcpy(pStr, pn);
}
}
myString::~myString() {
delete[] pStr;
pStr = 0;
size = 0;
}
void myString::set(const char* pn) {
if (pn == 0) {
delete[] pStr;
size = 0;
pStr = new char[1];
pStr[0] = '\0';
return;
}
int newSize = strlen(pn);
if (newSize != size) {
delete[] pStr;
pStr = new char[newSize + 1];
size = newSize;
}
strcpy(pStr, pn);
}
void myString::set(const myString& rStr) {
if (this == &rStr) {
return;
}
int newSize = rStr.size;
if (newSize != size) {
delete[] pStr;
pStr = new char[newSize + 1];
size = newSize;
}
strcpy(pStr, rStr.pStr);
}
void myString::print() const {
cout << pStr << ", " << size << endl;
}
char myString::get(int i) const {
if (i < 0 || i >= size) {
return '\0';
}
return pStr[i];
}
void myString::toUpper() {
for (int i = 0; i < size; i++) {
pStr[i] = toupper(pStr[i]);
}
}
bool myString::strcompare(const myString& s) {
if (size != s.size) {
return false;
}
return strcmp(pStr, s.pStr) == 0;
}
int main() {
myString s2, s1("Hello");
cout << s1.get(0) << endl; //输出H
s2.print(); //输出“空字符串”,0
s2.set("Hello world");
s2.print(); //输出“Hello world”
s1.toUpper();
s1.print(); //输出HELLO
s1.set(s2);
if (s2.strcompare(s1))
cout << "字符串相同";
else
cout << "字符串不同";
return 0;
}
以上使用了string的库函数,需要替换的话用循环重写即可。
运行结果:
BASH
root@lsj-nas2:/vol2/1000/c程/信息技术实践# cd "/vol2/1000/c程/信息技术实践/" && g++ 2-2.cpp -o 2-2 && "/vol2/1000/c程/信息技术实践/"2-2
2-2.cpp: In function ‘int main()’:
2-2.cpp:93:25: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
93 | myString s2, s1("Hello");
| ^~~~~~~
H
, 0
Hello world, 11
HELLO, 5
字符串相同
T3
定义点类
Point,包括私有成员int x, y; 及相关成员函数;定义圆类
Circle,私有数据成员包括圆心Point center和半径double radium; 和静态成员Pi = 3.14159; 公有成员函数实现以下功能:
重载各种构造函数,允许将多个圆按不同形式初始化。
定义常成员函数
show()输出信息,例如圆的相关信息定义常成员函数
area()计算圆的面积设计源判断点与圆的关系
judge(), 若p在圆内或圆上返回true,否则返回false。思考是友元函数还是成员函数?能否利用点距类计算距离的成员函数
也是比较简单的模拟,需要注意PI的初始化,以及构造函数的多态:
CPP
#include <cmath>
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public:
Point() : x(0), y(0) {
}
Point(int x, int y) : x(x), y(y) {
}
Point(const Point& p) : x(p.x), y(p.y) {
}
int getX() const {
return x;
}
int getY() const {
return y;
}
void setX(int x) {
this->x = x;
}
void setY(int y) {
this->y = y;
}
double distanceSquared(const Point& p) const {
// 消除精度问题
int dx = x - p.x;
int dy = y - p.y;
return dx * dx + dy * dy;
}
double distance(const Point& p) const {
return sqrt(distanceSquared(p));
}
};
class Circle {
private:
Point center;
double radium;
static const double Pi;
public:
Circle() : center(0, 0), radium(1.0) {
}
Circle(const Point& c, double r) : center(c), radium(r) {
}
Circle(int x, int y, double r) : center(x, y), radium(r) {
}
Circle(const Circle& c) : center(c.center), radium(c.radium) {
}
void setCenter(const Point& c) {
center = c;
}
void setCenter(int x, int y) {
center = Point(x, y);
}
void setRadium(double r) {
if (r > 0)
radium = r;
else
radium = 1.0;
}
Point getCenter() const {
return center;
}
double getRadium() const {
return radium;
}
void show() const {
cout << "Circle Information:" << endl;
cout << "Center: (" << center.getX() << ", " << center.getY() << ")"
<< endl;
cout << "Radium: " << radium << endl;
cout << "Area: " << area() << endl;
cout << "Pi: " << Pi << endl;
}
double area() const {
return Pi * radium * radium;
}
bool judge(const Point& p) const {
double distSq = center.distanceSquared(p);
return distSq <= radium * radium;
}
};
const double Circle::Pi = 3.14159;
// 测试代码【AI生成】
int main() {
// 测试Point类
Point p1(3, 4);
Point p2(0, 0);
Point p3(1, 1);
cout << "Point1: (" << p1.getX() << ", " << p1.getY() << ")" << endl;
cout << "Point2: (" << p2.getX() << ", " << p2.getY() << ")" << endl;
cout << "Distance between p1 and p2: " << p1.distance(p2) << endl;
cout << endl;
// 测试Circle类的各种构造函数
Circle c1; // 默认构造
Circle c2(Point(2, 3), 5.0); // 圆心+半径
Circle c3(4, 5, 3.5); // 坐标+半径
Circle c4(c2); // 拷贝构造
// 显示各圆信息
cout << "Circle c1 (default):" << endl;
c1.show();
cout << endl;
cout << "Circle c2:" << endl;
c2.show();
cout << endl;
cout << "Circle c3:" << endl;
c3.show();
cout << endl;
cout << "Circle c4 (copy of c2):" << endl;
c4.show();
cout << endl;
// 测试judge函数
cout << "Testing judge function:" << endl;
cout << "Point (" << p2.getX() << ", " << p2.getY() << ") in circle c2? "
<< (c2.judge(p2) ? "Yes" : "No") << endl;
cout << "Point (" << p3.getX() << ", " << p3.getY() << ") in circle c2? "
<< (c2.judge(p3) ? "Yes" : "No") << endl;
cout << "Point (" << p1.getX() << ", " << p1.getY() << ") in circle c2? "
<< (c2.judge(p1) ? "Yes" : "No") << endl;
// 测试边界情况(点在圆上)
Point p4(7, 3); // 距离圆心(2,3)为5,正好在圆上
cout << "Point (" << p4.getX() << ", " << p4.getY() << ") in circle c2? "
<< (c2.judge(p4) ? "Yes" : "No") << endl;
return 0;
}
为什么选择成员函数而非友元函数?
封装性更好:
成员函数可以直接访问类的私有成员(
center和radium),不需要通过公有接口友元函数虽然也能访问私有成员,但破坏了封装性
设计合理性:
judge()函数判断一个点是否在圆内,这个操作天然属于圆的行为从面向对象角度看,应该是"圆判断点"而不是"外部函数判断点和圆"
依赖关系:
成员函数可以直接使用
Point类的distanceSquared()方法代码更简洁,不需要额外的参数传递
