C++20练习代码
·
一.类的定义练习)(类的基本操作)
1.1String类定义
完成了String类的基本操作的定义,并进行检验。其中有些注意点:
1.显示类型转换static_cast<>();
2.NRVO:
具名返回值优化编译器会直接消除掉 result 这个局部变量的存在感,直接在外部调用者接收返回值的地方构造对象。零拷贝,零额外的析构,效率极高。 这在 C++17 中甚至被写入了语言标准(强制 RVO),保证一定不会发生拷贝。
3.strlen(char*)、strcpy(char*,char*)//赋值第二个字符串到第一个字符串中、strcmp(char*,char*)//一一比较两个字符串的每个字符的ASCII码
strcat(char*,char*)//追加第二个字符串到第一个字符串后面。
4.stong_ordering::(less\greater\equal)重载函数<=>时使用非常标准。
5.new,delete;new[],delete[];malloc,free成对使用绝不可混搭。
6.noexcept 指明函数绝不会返回报错
7.std::move()用作移动语义
#define _CRT_SECURE_NO_WARNINGS
#include<cstring>
#include<iostream>
#include<compare>
class String {
public:
//默认构造函数
String() {
size = 0;
ch = new char[1];
ch[0] = '0';
}
//赋值构造函数
String(const char* c)
{
if (c)
{
size = static_cast<int>(std::strlen(c));
ch = new char[size+1];
std::strcpy(ch, c);
}
else {
size = 0;
ch = new char[1];
ch[0] = '\0';
}
}
String(const String& c)//拷贝构造函数
{
size = c.size;
ch = new char[size + 1];
std::strcpy(ch, c.ch);
}
//移动构造函数
String(String&&s)noexcept//告诉编译器这个过程绝不会抛出异常
{
ch = s.ch;
size = s.size;
std::cout << "调用了移动构造\n";
s.ch = nullptr;
s.size = 0;
}
~String() {
delete[] ch;//析构数组
}
//拷贝赋值运算符
String& operator=(const String& s)
{
if (this != &s) {//两阶段解析机制,但这里是两个指针在进行比较。
delete[] ch;
size = s.size;
std::strcpy(ch, s.ch);
}
return *this;
}
//移动赋值运算符
String& operator=(String&& s) noexcept
{
if (this != &s) {
delete[]ch;
ch = s.ch;
size = s.size;
std::cout << "调用了移动构造\n";
s.ch = nullptr;
s.size = 0;
}
return *this;
}
String& operator=(const char* s)
{
if (s)
{
delete[] ch;
size = static_cast<int>(std::strlen(s));
ch = new char[size + 1];
std::strcpy(ch, s);
}
return *this;
}
//+重载
String operator+(const char* c)
{
String result;//默认构造函数
if (c)
{
result.size = this->size + static_cast<int>(std::strlen(c));
delete[] result.ch;
result.ch = new char[result.size + 1];
std::strcpy(result.ch, this->ch);
std::strcat(result.ch, c);//追加
}
else {
result = *this;
}
return result;//NRVO(具名返回值优化编译器会直接消除掉 result 这个局部变量的存在感,直接在外部调用者接收返回值的地方构造对象。零拷贝,零额外的析构,效率极高。 这在 C++17 中甚至被写入了语言标准(强制 RVO),保证一定不会发生拷贝。)
}
//重载两个String类相加
String operator+(const String& s)const
{
String result;
result.size = size + s.size;
delete[] result.ch;
result.ch = new char[result.size + 1];
std::strcpy(result.ch, ch);
std::strcat(result.ch, s.ch);
return result;
}
//实现将一个String类与一个C风格字符串相加
std::strong_ordering operator<=>(const String& S) const {
int cmp = std::strcmp(this->ch, S.ch);//将字符一个个比较
if (cmp < 0) {
return std::strong_ordering::less;
}
if (cmp > 0) {
return std::strong_ordering::greater;
}
return std::strong_ordering::equal;
}
bool operator==(const String& S) const {
return std::strcmp(this->ch, S.ch) == 0;
}
//返回底层C风格字符串
const char* c_str()const {
return ch;
}
//返回字符串长度
int length()const {
return size;
}
private:
int size;
char* ch;
};
int main()
{
String s1;
String s2{ "Hello" };
String s3{ s2 };
s1 = "World";
String s4 = s2 + "C++";
String s5 = { "Good " };
String s6 = { "morning" };
String s7 = s5 + s6;
String s8{ "keepworking" };
String s9 = std::move(s8);//移动构造
String s10{ "realword" };
s8 = std::move(s10);
std::cout << "s2:" << s2.c_str() << std::endl;
std::cout << "s1:" << s1.c_str() << std::endl;
std::cout << "s4:" << s4.c_str() << std::endl;
std::cout << "s7:" << s7.c_str() << std::endl;
std::cout << "s9:" << s9.c_str() << std::endl;
std::cout << "s8:" << s8.c_str() << std::endl;
if ((s2 <=> s1) == std::strong_ordering::less) {
std::cout << s2.c_str()
<< "is less than"
<< s1.c_str()
<< std::endl;
}
return 0;
}
1.2.Vector类
#include <iostream>
#include <cstddef>
#include <algorithm> // 为了 std::copy 和 std::swap
#include <stdexcept> // 为了 std::out_of_range报错
#include <iomanip> // 用于对齐输出
#include <string>
class Vector {
public:
// 1. 构造函数
Vector() = default;
explicit Vector(size_t capacity)
: data_{ capacity > 0 ? new int[capacity]() : nullptr },
size_{ 0 },
capacity_{ capacity } {
}
// 2. 拷贝构造函数 (深拷贝)
Vector(const Vector& other)
: data_{ other.capacity_ > 0 ? new int[other.capacity_] : nullptr },
size_{ other.size_ },
capacity_{ other.capacity_ } {
std::copy(other.data_, other.data_ + size_, data_);//std::copy 是 C++ 标准库 <algorithm> 头文件里提供的一个通用搬运工。将一个范围内的元素,复制到另一个地方。遵循 C++ 的左闭右开原则:复制从 $[first, last)$ 范围内的所有元素到以 result 开头的位置。std::copy(起始位置, 结束位置, 目标起始位置);
}
// 3. 移动构造函数 (利用交换逻辑)
Vector(Vector&& other) noexcept : Vector() {
swap(*this, other);
}
// 4. 赋值运算符 (Copy-and-Swap 惯用法)
// 注意:这里传值(by value)调用,自动根据传入的是左值还是右值
// 触发拷贝构造或移动构造,一个函数顶两个。
Vector& operator=(Vector other) noexcept {
swap(*this, other);
return *this;
}
// 5. 析构函数
~Vector() {
delete[] data_;
}
// 友情交换函数 (高效赋值的核心)
friend void swap(Vector& first, Vector& second) noexcept {
using std::swap;//std::swap 就是 C++ 里的“交换魔术师”。它的唯一任务,就是让两个变量的值原地互换。
swap(first.data_, second.data_);
swap(first.size_, second.size_);
swap(first.capacity_, second.capacity_);
}
// --- 功能函数 ---
void push_back(int value) {
if (size_ == capacity_) {
// 扩容逻辑:1.5倍或2倍是比较理想的平衡点
reserve(capacity_ == 0 ? 1 : capacity_ * 2);
}
data_[size_++] = value;
}
void reserve(size_t new_cap) {
if (new_cap <= capacity_) return;
int* new_data = new int[new_cap];
if (data_) {
std::copy(data_, data_ + size_, new_data);
delete[] data_;
}
data_ = new_data;
capacity_ = new_cap;
}
// --- 访问器 (Const Correctness) ---
// 区分只读和读写
int& operator[](size_t index) { return data_[index]; }
const int& operator[](size_t index) const { return data_[index]; }
int& at(size_t index) {
if (index >= size_) throw std::out_of_range("Vector index out of range");
return data_[index];
}
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
bool empty() const { return size_ == 0; }
// --- 迭代器 (为了支持 Range-based for) ---
int* begin() { return data_; }
const int* begin() const { return data_; }
int* end() { return data_ + size_; }
const int* end() const { return data_ + size_; }
private:
int* data_ = nullptr;
size_t size_ = 0;
size_t capacity_ = 0;
};
// 打印 Vector 状态的辅助函数
void printVector(const std::string& name, const Vector& v) {
std::cout << std::left << std::setw(15) << name
<< " | Size: " << v.size()
<< " | Capacity: " << v.capacity()
<< " | Elements: [ ";
for (size_t i = 0; i < v.size(); ++i) {
std::cout << v[i] << " ";
}
std::cout << "]" << (v.empty() ? " (Empty)" : "") << std::endl;
}
int main() {
std::cout << "=== 1. 构造函数与基础功能测试 ===" << std::endl;
Vector v1; // 默认构造
printVector("v1 (Default)", v1);
Vector v2(5); // 参数化构造
printVector("v2 (Capacity 5)", v2);
for (int i = 1; i <= 6; ++i) {
v1.push_back(i * 10); // 测试 push_back 和 动态扩容
}
printVector("v1 (After push)", v1);
std::cout << "\n=== 2. 元素访问测试 ===" << std::endl;
std::cout << "v1[2] (下标访问): " << v1[2] << std::endl;
try {
std::cout << "v1.at(2) (安全访问): " << v1.at(2) << std::endl;
std::cout << "v1.at(10) (越界测试): ";
std::cout << v1.at(10) << std::endl; // 这行会抛出异常
}
catch (const std::out_of_range& e) {
std::cout << "捕获异常: " << e.what() << std::endl;
}
std::cout << "\n=== 3. 拷贝语义测试 (深拷贝) ===" << std::endl;
Vector v3 = v1; // 拷贝构造
v3[0] = 999; // 修改 v3 不应影响 v1
printVector("v1 (Original)", v1);
printVector("v3 (Copy of v1)", v3);
Vector v4;
v4 = v1; // 拷贝赋值 (Copy-and-Swap)
printVector("v4 (Assigned v1)", v4);
std::cout << "\n=== 4. 移动语义测试 (资源夺取) ===" << std::endl;
// 使用 std::move 将 v3 标记为可移动
Vector v5 = std::move(v3);
std::cout << "执行 v5 = std::move(v3) 后:" << std::endl;
printVector("v5 (Moved to)", v5);
printVector("v3 (Moved from)", v3); // v3 应该变为空
std::cout << "\n=== 5. 扩容(reserve)与迭代器测试 ===" << std::endl;
Vector v6;
v6.reserve(100); // 预留空间
v6.push_back(1);
v6.push_back(2);
v6.push_back(3);
printVector("v6 (Reserved)", v6);
std::cout << "使用 Range-based for 循环遍历 v6: ";
for (auto x : v6) { // 这行成功运行的前提是你有 begin() 和 end()
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
1.3.Complex复数类
二.类的继承及多态练习
三.模板练习(以及泛型编程)
3.1类模板
3.2模板函数
3.3模板对象(lambda)
3.4模板变量
3.5别名
3.6编译时if(if constexpr)
四.类型转换练习
五.错误处理练习
更多推荐

所有评论(0)