Lab7: 面向对象程序构造方法及创新应用 (基础)
1、实现一个自定义字符串类型 String,使之具有与 int 等基本类型相同的使用方式。(注:含类、构造、析构、重载等机制运用)
需要分清默认构造函数、拷贝构造函数、带参数构造函数和重载的赋值运算符。
其中加法重载稍微复杂一点。
代码
#include <iostream>
#include <cstring>
class String {
private:
char* data; // 字符串数据
size_t length; // 字符串长度
public:
// 默认构造函数
String() : data(NULL), length(0) {puts("默认构造");}
// 构造函数
String(const char* str) {
puts("带参数构造");
length = strlen(str); // 获取字符串长度
data = new char[length + 1]; // 分配内存
strcpy(data, str); // 复制字符串
}
// 拷贝构造函数
String(const String& other) {
length = other.length; // 获取字符串长度
data = new char[length + 1]; // 分配内存
strcpy(data, other.data); // 复制字符串
}
// 析构函数
~String() {
puts("析构");
delete[] data; // 释放内存
}
// 重载相加运算符
String operator+(const String& other) const {
String result;
result.length = length + other.length; // 计算结果长度
result.data = new char[result.length + 1]; // 分配内存
strcpy(result.data, data); // 复制当前字符串
strcat(result.data, other.data); // 连接另一个字符串
return result;
}
// 重载相等运算符
bool operator==(const String& other) const {
return strcmp(data, other.data) == 0;
}
// 重载输出运算符
friend std::ostream& operator<<(std::ostream& os, const String& str) {
os << str.data;
return os;
}
};
int main() {
String str1 = "Hello";
String str2 = "World";
String str3 = str1 + str2;
String str4;
//str4 = str1 + str2; 这一行要用到重载赋值运算符
std::cout << str1 << std::endl;
std::cout << str2 << std::endl;
std::cout << str3 << std::endl;
if (str1 == str2) {
std::cout << "str1 and str2 are equal" << std::endl;
} else {
std::cout << "str1 and str2 are not equal" << std::endl;
}
return 0;
}
/*
// 重载赋值运算符
String& operator=(const String& other) {
if (this != &other) {
delete[] data; // 释放原有内存
length = other.length; // 获取字符串长度
data = new char[length + 1]; // 分配新内存
strcpy(data, other.data); // 复制字符串
}
return *this;
}
*/
输出
2、实现一个“字”类型,并通过继承和多态机制分别实现“字”的不同显示、不同字体、不同大小等等。
在上述代码中,我们定义了一个基类 Character,它表示一个字,并具有纯虚函数 display() 用于显示字的内容。然后,我们派生出了三个子类:SongTiCharacter(宋体字)、HeiTiCharacter(黑体字)和 BoldCharacter(加粗字)。每个子类都重写了基类的 display() 函数,以实现不同的显示方式。
在 main() 函数中,我们创建了一个指向基类的指针数组 characters,并分别使用派生类的构造函数创建了三个不同的字对象。通过循环遍历数组,并调用 display() 函数,实现了多态的效果。最后,记得释放动态分配的内存。
代码
#include <iostream>
#include <string>
// 基类:字
class Character {
protected:
std::string content;
public:
Character(const std::string& content) : content(content) {}
virtual ~Character() {}
virtual void display() const = 0;
};
// 派生类:宋体字
class SongTiCharacter : public Character {
public:
SongTiCharacter(const std::string& content) : Character(content) {}
void display() const {
std::cout << "宋体字:" << content << std::endl;
}
};
// 派生类:黑体字
class HeiTiCharacter : public Character {
public:
HeiTiCharacter(const std::string& content) : Character(content) {}
void display() const {
std::cout << "黑体字:" << content << std::endl;
}
};
// 派生类:加粗字
class BoldCharacter : public Character {
public:
BoldCharacter(const std::string& content) : Character(content) {}
void display() const {
std::cout << "加粗字:" << content << std::endl;
}
};
int main() {
Character* characters[3];
characters[0] = new SongTiCharacter("你好");
characters[1] = new HeiTiCharacter("Hello");
characters[2] = new BoldCharacter("Bonjour");
for (int i = 0; i < 3; i++) {
characters[i]->display();
delete characters[i];
}
return 0;
}
输出
3、I/O 流基本应用
通过文件流读取两个含有若干整数的文本文件,将这些整数排序后写入另一个文本文件中。
代码
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
int main() {
// 读取第一个文件的整数
std::ifstream file1("file1.txt");
if (!file1) {
std::cerr << "无法打开文件1" << std::endl;
return 1;
}
std::vector<int> numbers;
int num;
while (file1 >> num) {
numbers.push_back(num);
}
file1.close();
// 读取第二个文件的整数
std::ifstream file2("file2.txt");
if (!file2) {
std::cerr << "无法打开文件2" << std::endl;
return 1;
}
while (file2 >> num) {
numbers.push_back(num);
}
file2.close();
// 对整数进行排序
std::sort(numbers.begin(), numbers.end());
// 写入结果到第三个文件
std::ofstream outputFile("output.txt");
if (!outputFile) {
std::cerr << "无法打开输出文件" << std::endl;
return 1;
}
for (size_t i = 0; i < numbers.size(); i++) {
outputFile << numbers[i] << " ";
}
outputFile.close();
std::cout << "排序完成,结果已写入output.txt文件" << std::endl;
return 0;
}
输出(输入输出均在文件内)
排序完成,结果已写入output.txt文件
1 2 3 4 5 6 7 8
4、通过扩展方式定义一个自己的异常类并进行验证。
在这个示例中,我们定义了一个自定义的异常类 MyException,它继承自 std::exception。 what() 函数返回异常消息的字符串表示。
在 divide() 函数中,如果除数为零,我们抛出一个 MyException 异常,并将异常消息作为参数传递给异常的构造函数。
代码
#include <iostream>
#include <stdexcept>
// 自定义异常类
class MyException : public std::exception {
private:
std::string message;
public:
MyException(const std::string& msg) : message(msg) {}
~MyException() throw() {}
const char* what() const throw() {
return message.c_str();
}
};
// 函数:除法运算
double divide(double dividend, double divisor) {
if (divisor == 0.0) {
throw MyException("除数不能为零");
}
return dividend / divisor;
}
int main() {
try {
double result = divide(10.0, 0.0);
std::cout << "结果:" << result << std::endl;
} catch (const MyException& ex) {
std::cerr << "捕获到自定义异常:" << ex.what() << std::endl;
}
return 0;
}