一.类的定义练习)(类的基本操作)

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)

四.类型转换练习

五.错误处理练习

更多推荐