c++学习笔记(5)

151、模板类的示例-栈

示例:

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// typedef string DataType; // 定义栈元素的数据类型。

template <class DataType>

class Stack // 栈类

{

private:

DataType* items; // 栈数组。

int stacksize; // 栈实际的大小。

int top; // 栈顶指针。

public:

// 构造函数:1)分配栈数组内存;2)把栈顶指针初始化为 0。

Stack(int size) :stacksize(size), top(0) {

items = new DataType[stacksize];

}~Stack() {

delete [] items; items = nullptr;

}

bool isempty() const { // 判断栈是否为空。

return top == 0;

}

bool isfull() const { // 判断栈是否已满。

return top == stacksize;

}

bool push(const DataType& item) { // 元素入栈。

if (top < stacksize) { items[top++] = item; return true; }

return false;

}

bool pop(DataType& item) { // 元素出栈。

if (top > 0) { item = items[--top]; return true; }

return false;

}

};

int main()

{

Stack<string> ss(5); // 创建栈对象,大小是 5。

// 元素入栈。

// ss.push(1); ss.push(2); ss.push(3); ss.push(4); ss.push(5);

ss.push("西施"); ss.push("冰冰"); ss.push("幂幂"); ss.push("金莲");

// 元素出栈。

string item;

while (ss.isempty() == false)

{

ss.pop(item); cout << "item = " << item << endl;

}

}

152、模板类的示例-数组

类模板可以有非通用类型参数:1)通常是整型(C++20 标准可以用其它的类型);2)实例化模板

时必须用常量表达式;3)模板中不能修改参数的值;4)可以为非通用类型参数提供默认值。

优点:在栈上分配内存,易维护,执行速度快,合适小型数组。

缺点:在程序中,不同的非通用类型参数将导致编译器生成不同的类。

构造函数的方法更通用,因为数据的大小是类的成员(而不是硬编码),可以创建数组大小可变的类。

示例:

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

template <class T,int len=10>

class Array

{

private:

T items[len]; // 数组元素。

public:

Array() {} // 默认构造函数。

~Array() {} // 析构函数

T& operator[](int ii) { return items[ii]; } // 重载操作符[],可以修改数组中的元素。

const T& operator[](int ii) const { return items[ii]; } // 重载操作符[],不能修改数组中的元

素。

};

template <class T>

class Vector

{

private:

int len; // 数组元素的个数。

T* items; // 数组元素。

public:

// 默认构造函数,分配内存。

Vector(int size=10):len(size) {

items = new T[len];

}~Vector() { // 析构函数

delete[] items; items = nullptr;

}

void resize(int size) { // 护展数组的内存空间。

if (size <= len) return; // 只能往更大扩展。

T* tmp = new T[size]; // 分配更大的内存空间。

for (int ii = 0; ii < len; ii++) tmp[ii] = items[ii]; // 把原来数组中的元素复制到新数组。

delete[] items; // 释放原来的数组。

items = tmp; // 让数组指针指向新数组。

len = size; // 扩展后的数组长度。

}

int size() const { return len; } // 获取数组长度。

T& operator[](int ii) { // 重载操作符[],可以修改数组中的元素。

if (ii >= len) resize(ii + 1); // 扩展数组。

return items[ii];

}

const T& operator[](int ii) const { return items[ii]; } // 重载操作符[],不能修改数组中的元

素。

};

int main()

{

// Array<string,10> aa; // 创建模板类 Array 的对象。

Vector<int> aa(1); // 创建模板类 Vector 的对象。

aa[0] = 5; aa[1] = 8; aa[2] = 3; aa[3] = 2; aa[4] = 7;

// aa[0] = "西施"; aa[1] = "冰冰"; aa[2] = "幂幂"; aa[3] = "金莲"; aa[4] = "小乔";

for (int ii=0; ii<5;ii++) cout << "aa[" << ii << "]=" << aa[ii] << endl;

}

153、嵌套和递归使用模板类

在 C++11 之前,嵌套使用模板类的时候,> >之间要加空格。

示例:

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

template <class DataType>

class Stack // 栈类

{

private:

DataType* items; // 栈数组。

int stacksize; // 栈实际的大小。

int top; // 栈顶指针。

public:

// 构造函数:1)分配栈数组内存;2)把栈顶指针初始化为 0。

Stack(int size = 3) :stacksize(size), top(0) {

items = new DataType[stacksize];

}~Stack() {

delete[] items; items = nullptr;

}

Stack& operator=(const Stack& v) // 重载赋值运算符函数,实现深拷贝。

{

delete[] items; // 释放原内存。

stacksize = v.stacksize; // 栈实际的大小。

items = new DataType[stacksize]; // 重新分配数组。

for (int ii = 0; ii < stacksize; ii++) items[ii] = v.items[ii]; // 复制数组中的元素。

top = v.top; // 栈顶指针。

return *this;

}

bool isempty() const { // 判断栈是否为空。

return top == 0;

}

bool isfull() const { // 判断栈是否已满。

return top == stacksize;

}

bool push(const DataType& item) { // 元素入栈。

if (top < stacksize) { items[top++] = item; return true; }

return false;

}

bool pop(DataType& item) { // 元素出栈。

if (top > 0) { item = items[--top]; return true; }

return false;

}

};

template <class T>

class Vector // 动态数组。

{

private:

int len; // 数组元素的个数。

T* items; // 数组元素。

public:

// 默认构造函数,分配内存。

Vector(int size = 2) :len(size) {

items = new T[len];

}~Vector() { // 析构函数

delete[] items; items = nullptr;

}

Vector& operator=(const Vector& v) // 重载赋值运算符函数,实现深拷贝。

{

delete[] items; // 释放原内存。

len = v.len; // 数组实际的大小。

items = new T[len]; // 重新分配数组。

for (int ii = 0; ii < len; ii++) items[ii] = v.items[ii]; // 复制数组中的元素。

return *this;

}

void resize(int size) { // 护展数组的内存空间。

if (size <= len) return; // 只能往更大扩展。

T* tmp = new T[size]; // 分配更大的内存空间。

for (int ii = 0; ii < len; ii++) tmp[ii] = items[ii]; // 把原来数组中的元素复制到新数组。

delete[] items; // 释放原来的数组。

items = tmp; // 让数组指针指向新数组。

len = size; // 扩展后的数组长度。

}

int size() const { return len; } // 获取数组长度。

T& operator[](int ii) { // 重载操作符[],可以修改数组中的元素。

if (ii >= len) resize(ii + 1); // 扩展数组。

return items[ii];

}

const T& operator[](int ii) const { return items[ii]; } // 重载操作符[],不能修改数组中的元

素。

};

int main()

{

// Vector 容器的大小缺省值是 2,Stack 容器的大小缺省值是 3。

// 创建 Vector 容器,容器中的元素用 Stack<string>。

Vector<Stack<string>> vs; // C++11 之前,>>之间要加空格。

// 手工的往容器中插入数据。

vs[0].push("西施 1"); vs[0].push("西施 2"); vs[0].push("西施 3"); // vs 容器中的第 0

个栈。

vs[1].push("西瓜 1"); vs[1].push("西瓜 2"); vs[1].push("西瓜 3"); // vs 容器中的第 1

个栈。

vs[2].push("冰冰"); vs[2].push("幂幂"); //

vs 容器中的第 2 个栈。

// 用嵌套的循环,把 vs 容器中的数据显示出来。

for (int ii = 0; ii < vs.size(); ii++) // 遍历 Vector 容器。

{

while (vs[ii].isempty() == false) // 遍历 Stack 容器。

{

string item; vs[ii].pop(item); cout << "item = " << item << endl;

}

}

// 创建 Stack 容器,容器中的元素用 Vector<string>。

Stack<Vector<string>> sv;

Vector<string> tmp; // 栈的元素,临时 Vector<string>容器。

// 第一个入栈的元素。

tmp[0] = "西施 1"; tmp[1] = "西施 2"; sv.push(tmp);

// 第二个入栈的元素。

tmp[0] = "西瓜 1"; tmp[1] = "西瓜 2"; sv.push(tmp);

// 第三个入栈的元素。

tmp[0] = " 冰 冰 1"; tmp[1] = " 冰 冰 2"; tmp[2] = " 冰 冰 3"; tmp[3] = " 冰 冰 4";

sv.push(tmp);

// 用嵌套的循环,把 sv 容器中的数据显示出来。

while (sv.isempty() == false)

{

sv.pop(tmp); // 出栈一个元素,放在临时容器中。

for (int ii = 0; ii < tmp.size(); ii++) // 遍历临时 Vector<string>容器,显示容器中每个

元素的值。

cout << " vs[" << ii << "] = " << tmp[ii] << endl;

}

// 创建 Vector 容器,容器中的元素用 Vector<string>。

Vector<Vector<string>> vv; // 递归使用模板类。

vv[0][0] = "西施 1"; vv[0][1] = "西施 2"; vv[0][2] = "西施 3";

vv[1][0] = "西瓜 1"; vv[1][1] = "西瓜 2";

vv[2][0] = "冰冰 1"; vv[2][1] = "冰冰 2"; vv[2][2] = "冰冰 3"; vv[2][3] = "冰冰 4";

// 用嵌套的循环,把 vv 容器中的数据显示出来。

for (int ii = 0; ii < vv.size(); ii++)

{

for (int jj = 0; jj < vv[ii].size(); jj++)

// cout << " vv[" << ii << "][" << jj << "] = " << vv[ii][jj] << endl;

cout << vv[ii][jj] << " ";

cout << endl;

}

}

154、模板类具体化

模板类具体化(特化、特例化)有两种:完全具体化和部分具体化。

语法请见示例程序。

具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类。

具体化的模板类,成员函数类外实现的代码应该放在源文件中。

示例:

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// 类模板

template<class T1, class T2>

class AA { // 类模板。

public:

T1 m_x;

T2 m_y;

AA(const T1 x, const T2 y) :m_x(x), m_y(y) { cout << "类模板:构造函数。\n"; }

void show() const;

};

template<class T1, class T2>

void AA<T1, T2>::show() const { // 成员函数类外实现。

cout << "类模板:x = " << m_x << ", y = " << m_y << endl;

}

/

// 类模板完全具体化

template<>

class AA<int, string> {

public:

int m_x;

string m_y;

AA(const int x, const string y) :m_x(x), m_y(y) { cout << "完全具体化:构造函数。\n"; }

void show() const;

};

void AA<int, string>::show() const { // 成员函数类外实现。

cout << "完全具体化:x = " << m_x << ", y = " << m_y << endl;

}

/

// 类模板部分具体化

template<class T1>

class AA<T1, string> {

public:

T1 m_x;

string m_y;

AA(const T1 x, const string y) :m_x(x), m_y(y) { cout << "部分具体化:构造函数。\n"; }

void show() const;

};

template<class T1>

void AA<T1, string>::show() const { // 成员函数类外实现。

cout << "部分具体化:x = " << m_x << ", y = " << m_y << endl;

}

/

int main()

{

// 具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类。

AA<int, string> aa1(8, "我是一只傻傻鸟。"); // 将使用完全具体化的类。

AA<char, string> aa2(8, "我是一只傻傻鸟。"); // 将使用部分具体化的类。

AA<int, double> aa3(8, 999999); // 将使用模板类。

}

156、模板类与继承

1)模板类继承普通类(常见)。

2)普通类继承模板类的实例化版本。

3)普通类继承模板类。(常见)

4)模板类继承模板类。

5)模板类继承模板参数给出的基类(不能是模板类)。

示例:

1)模板类继承普通类

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

class AA // 普通类 AA。

{

public:

int m_a;

AA(int a) :m_a(a) { cout << "调用了 AA 的构造函数。\n"; }

void func1() { cout << "调用了 func1()函数:m_a=" << m_a << endl;; }

};

template<class T1, class T2>

class BB:public AA // 模板类 BB。

{

public:

T1 m_x;

T2 m_y;

BB(const T1 x, const T2 y,int a) : AA(a) , m_x(x), m_y(y) { cout << "调用了 BB 的构造函数。

\n"; }

void func2() const { cout << "调用了 func2()函数:x = " << m_x << ", y = " << m_y <<

endl; }

};

int main()

{

BB<int, string> bb(8, "我是一只傻傻鸟。",3);

bb.func2();

bb.func1();

}

2)普通类继承模板类的实例化版本

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

template<class T1, class T2>

class BB // 模板类 BB。

{

public:

T1 m_x;

T2 m_y;

BB(const T1 x, const T2 y) : m_x(x), m_y(y) { cout << "调用了 BB 的构造函数。\n"; }

void func2() const { cout << "调用了 func2()函数:x = " << m_x << ", y = " << m_y <<

endl; }

};

class AA:public BB<int,string> // 普通类 AA。

{

public:

int m_a;

AA(int a,int x,string y) : BB(x,y),m_a(a) { cout << "调用了 AA 的构造函数。\n"; }

void func1() { cout << "调用了 func1()函数:m_a=" << m_a << endl;; }

};

int main()

{

AA aa(3,8, "我是一只傻傻鸟。");

aa.func1();

aa.func2();

}

3)普通类继承模板类。

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

template<class T1, class T2>

class BB // 模板类 BB。

{

public:

T1 m_x;

T2 m_y;

BB(const T1 x, const T2 y) : m_x(x), m_y(y) { cout << "调用了 BB 的构造函数。\n"; }

void func2() const { cout << "调用了 func2()函数:x = " << m_x << ", y = " << m_y <<

endl; }

};

template<class T1, class T2>

class AA:public BB<T1,T2> // 普通类 AA 变成了模板类,才能继承模板类。

{

public:

int m_a;

AA(int a, const T1 x, const T2 y) : BB<T1,T2>(x,y),m_a(a) { cout << "调用了 AA 的构造函数。

\n"; }

void func1() { cout << "调用了 func1()函数:m_a=" << m_a << endl;; }

};

int main()

{

AA<int,string> aa(3,8, "我是一只傻傻鸟。");

aa.func1();

aa.func2();

}

4)模板类继承模板类。

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

template<class T1, class T2>

class BB // 模板类 BB。

{

public:

T1 m_x;

T2 m_y;

BB(const T1 x, const T2 y) : m_x(x), m_y(y) { cout << "调用了 BB 的构造函数。\n"; }

void func2() const { cout << "调用了 func2()函数:x = " << m_x << ", y = " << m_y <<

endl; }

};

template<class T1, class T2>

class AA:public BB<T1,T2> // 普通类 AA 变成了模板类,才能继承模板类。

{

public:

int m_a;

AA(int a, const T1 x, const T2 y) : BB<T1,T2>(x,y),m_a(a) { cout << "调用了 AA 的构造函数。

\n"; }

void func1() { cout << "调用了 func1()函数:m_a=" << m_a << endl;; }

};

template<class T, class T1, class T2>

class CC :public BB<T1, T2> // 模板类继承模板类。

{

public:

T m_a;

CC(const T a, const T1 x, const T2 y) : BB<T1, T2>(x, y), m_a(a) { cout << "调用了 CC 的构

造函数。\n"; }

void func3() { cout << "调用了 func3()函数:m_a=" << m_a << endl;; }

};

int main()

{

CC<int,int,string> cc(3,8, "我是一只傻傻鸟。");

cc.func3();

cc.func2();

}

5)模板类继承模板参数给出的基类

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

class AA {

public:

AA() { cout << "调用了 AA 的构造函数 AA()。\n"; }

AA(int a) { cout << "调用了 AA 的构造函数 AA(int a)。\n"; }

};

class BB {

public:

BB() { cout << "调用了 BB 的构造函数 BB()。\n"; }

BB(int a) { cout << "调用了 BB 的构造函数 BB(int a)。\n"; }

};

class CC {

public:

CC() { cout << "调用了 CC 的构造函数 CC()。\n"; }

CC(int a) { cout << "调用了 CC 的构造函数 CC(int a)。\n"; }

};

template<class T>

class DD {

public:

DD() { cout << "调用了 DD 的构造函数 DD()。\n"; }

DD(int a) { cout << "调用了 DD 的构造函数 DD(int a)。\n"; }

};

template<class T>

class EE : public T { // 模板类继承模板参数给出的基类。

public:

EE() :T() { cout << "调用了 EE 的构造函数 EE()。\n"; }

EE(int a) :T(a) { cout << "调用了 EE 的构造函数 EE(int a)。\n"; }

};

int main()

{

EE<AA> ea1; // AA 作为基类。

EE<BB> eb1; // BB 作为基类。

EE<CC> ec1; // CC 作为基类。

EE<DD<int>> ed1; // EE<int>作为基类。

// EE<DD> ed1; // DD 作为基类,错误。

}

157、模板类与函数

模板类可以用于函数的参数和返回值,有三种形式:

1)普通函数,参数和返回值是模板类的实例化版本。

2)函数模板,参数和返回值是某种的模板类。

3)函数模板,参数和返回值是任意类型(支持普通类和模板类和其它类型)。

示例:

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

template<class T1, class T2>

class AA // 模板类 AA。

{

public:

T1 m_x;

T2 m_y;

AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }

void show() const { cout << "show() x = " << m_x << ", y = " << m_y << endl; }

};

// 采用普通函数,参数和返回值是模板类 AA 的实例化版本。

AA<int, string> func(AA<int, string>& aa)

{

aa.show();

cout << "调用了 func(AA<int, string> &aa)函数。\n";

return aa;

}

// 函数模板,参数和返回值是的模板类 AA。

template <typename T1,typename T2>

AA<T1, T2> func(AA<T1, T2>& aa)

{

aa.show();

cout << "调用了 func(AA<T1, T2> &aa)函数。\n";

return aa;

}

// 函数模板,参数和返回值是任意类型。

template <typename T>

T func(T &aa)

{

aa.show();

cout << "调用了 func(AA<T> &aa)函数。\n";

return aa;

}

int main()

{

AA<int, string> aa(3, "我是一只傻傻鸟。");

func(aa);

}

158、模板类与友元

模板类的友元函数有三类:

1)非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数。

2)约束模板友元:模板类实例化时,每个实例化的类对应一个友元函数。

3)非约束模板友元:模板类实例化时,如果实例化了 n 个类,也会实例化 n 个友元函数,每个实例

化的类都拥有 n 个友元函数。

1)非模板友元示例:

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

template<class T1, class T2>

class AA

{

T1 m_x;

T2 m_y;

public:

AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }

// 非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数,只能在类内实现。

friend void show(const AA<T1, T2>& a)

{

cout << "x = " << a.m_x << ", y = " << a.m_y << endl;

}

/* friend void show(const AA<int, string>& a);

friend void show(const AA<char, string>& a);*/

};

//void show(const AA<int, string>& a)

//{

// cout << "x = " << a.m_x << ", y = " << a.m_y << endl;

//}

//

//void show(const AA<char, string>& a)

//{

// cout << "x = " << a.m_x << ", y = " << a.m_y << endl;

//}

int main()

{

AA<int, string> a(88, "我是一只傻傻鸟。");

show(a);

AA<char, string> b(88, "我是一只傻傻鸟。");

show(b);

}

2)约束模板友元示例:

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// 约束模板友元:模板类实例化时,每个实例化的类对应一个友元函数。

template <typename T>

void show(T& a); // 第一步:在模板类的定

义前面,声明友元函数模板。

template<class T1, class T2>

class AA // 模板类 AA。

{

friend void show<>(AA<T1, T2>& a); // 第二步:在模板类中,再次声明友元函

数模板。

T1 m_x;

T2 m_y;

public:

AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }

};

template<class T1, class T2>

class BB // 模板类 BB。

{

friend void show<>(BB<T1, T2>& a); // 第二步:在模板类中,再次声明友元函数

模板。

T1 m_x;

T2 m_y;

public:

BB(const T1 x, const T2 y) : m_x(x), m_y(y) { }

};

template <typename T> // 第三步:友元函数模板的定义。

void show(T& a)

{

cout << "通用:x = " << a.m_x << ", y = " << a.m_y << endl;

}

template <> // 第三步:具体化版本。

void show(AA<int, string>& a)

{

cout << "具体 AA<int, string>:x = " << a.m_x << ", y = " << a.m_y << endl;

}

template <> // 第三步:具体化版本。

void show(BB<int, string>& a)

{

cout << "具体 BB<int, string>:x = " << a.m_x << ", y = " << a.m_y << endl;

}

int main()

{

AA<int, string> a1(88, "我是一只傻傻鸟。");

show(a1); // 将使用具体化的版本。

AA<char, string> a2(88, "我是一只傻傻鸟。");

show(a2); // 将使用通用的版本。

BB<int, string> b1(88, "我是一只傻傻鸟。");

show(b1); // 将使用具体化的版本。

BB<char, string> b2(88, "我是一只傻傻鸟。");

show(b2); // 将使用通用的版本。

}

3)非约束模板友元

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

// 非类模板约束的友元函数,实例化后,每个函数都是每个每个类的友元。

template<class T1, class T2>

class AA

{

template <typename T> friend void show(T& a); // 把函数模板设置为友元。

T1 m_x;

T2 m_y;

public:

AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }

};

template <typename T> void show(T& a) // 通用的函数模板。

{

cout << "通用:x = " << a.m_x << ", y = " << a.m_y << endl;

}

template <>void show(AA<int, string>& a) // 函数模板的具体版本。

{

cout << "具体<int, string>:x = " << a.m_x << ", y = " << a.m_y << endl;

}

int main()

{

AA<int, string> a(88, "我是一只傻傻鸟。");

show(a); // 将使用具体化的版本。

AA<char, string> b(88, "我是一只傻傻鸟。");

show(b); // 将使用通用的版本。

}

159、成员模板类

示例:

#include <iostream> // 包含头文件。

using namespace std; // 指定缺省的命名空间。

template<class T1, class T2>

class AA // 类模板 AA。

{

public:

T1 m_x;

T2 m_y;

AA(const T1 x, const T2 y) : m_x(x), m_y(y) {}

void show() { cout << "m_x=" << m_x << ",m_y=" << m_y << endl; }

template<class T>

class BB

{

public:

T m_a;

T1 m_b;

BB() {}

void show();

};

BB<string> m_bb;

template<typename T>

void show(T tt);

};

template<class T1, class T2>

template<class T>

void AA<T1,T2>::BB<T>::show() {

cout << "m_a=" << m_a << ",m_b=" << m_b << endl;

}

template<class T1, class T2>

template<typename T>

void AA<T1,T2>::show(T tt) {

cout << "tt=" << tt << endl;

cout << "m_x=" << m_x << ",m_y=" << m_y << endl;

m_bb.show();

}

int main()

{

AA<int, string> a(88, "我是一只傻傻鸟。");

a.show();

a.m_bb.m_a = "我有一只小小鸟。";

a.m_bb.show();

a.show("你是一只什么鸟?");

}

相关推荐
努力变厉害的小超超2 小时前
ArkTS中的组件基础、状态管理、样式处理、class语法以及界面渲染
笔记·鸿蒙
秃头佛爷2 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
dayouziei4 小时前
java的类加载机制的学习
java·学习
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq5 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
aloha_7896 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
青花瓷7 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
dsywws7 小时前
Linux学习笔记之vim入门
linux·笔记·学习
晨曦_子画8 小时前
3种最难学习和最容易学习的 3 种编程语言
学习