- C++
C++ 高级结构体与类编程教程
- 2025-5-29 11:49:30 @
🧱 C++ 高级结构体与类编程教程
📚 适合初学者到中级开发者的 C++ 结构体高级用法教程
🧑💻 涵盖:结构体定义、构造函数、析构函数、explicit 关键字、模板结构体、运算符重载等内容。
🕒 当前时间:2025年5月29日,星期四11时47分
📌 一、结构体(Struct)基础回顾
在 C++ 中,struct
是一种用户自定义的数据类型,可以包含多个不同类型的成员变量。
✅ 示例:
struct Point {
int x;
int y;
void print() const {
std::cout << "Point(" << x << ", " << y << ")" << std::endl;
}
};
🔹 struct
和 class
的区别在于默认访问权限:
struct
成员默认是public
class
成员默认是private
🔨 二、构造函数(Constructor)
构造函数用于初始化结构体或类的成员变量。
✅ 示例:
struct Point {
int x;
int y;
// 构造函数
Point(int x_val = 0, int y_val = 0) : x(x_val), y(y_val) {}
};
🔹 使用方式:
Point p1; // 默认值 (0, 0)
Point p2(3, 4); // 初始化为 (3, 4)
🧹 三、释放函数(Destructor)
当对象生命周期结束时,析构函数会被自动调用,用于释放资源(如内存、文件句柄等)。
✅ 示例:
struct Data {
int* buffer;
Data(int size) {
buffer = new int[size];
}
~Data() {
delete[] buffer; // 释放动态分配的内存
}
};
🔹 析构函数不能有参数,也不能被重载。
🔒 四、explicit 关键字详解
explicit
防止隐式类型转换。
❗问题示例:
struct Point {
int x, y;
Point(int val) : x(val), y(val) {}
};
void printPoint(Point p) {
p.print();
}
printPoint(5); // 编译器会自动将 5 转换为 Point(5)
✅ 加上 explicit:
explicit Point(int val) : x(val), y(val) {}
此时 printPoint(5)
会报错,必须显式转换:
printPoint(Point(5)); // 正确
🧩 五、结构体模板(Template Struct)
模板允许我们创建通用的结构体,支持多种数据类型。
✅ 示例:
template <typename T>
struct Pair {
T first;
T second;
Pair(T a, T b) : first(a), second(b) {}
void print() const {
std::cout << "Pair(" << first << ", " << second << ")" << std::endl;
}
};
🔹 使用方式:
Pair<int> p1(10, 20);
Pair<std::string> p2("Hello", "World");
➕ 六、重载运算符(Operator Overloading)
通过重载运算符,我们可以让结构体像基本类型一样使用操作符。
✅ 示例:重载 +
运算符
struct Point {
int x, y;
Point(int x_val = 0, int y_val = 0) : x(x_val), y(y_val) {}
// 重载 + 运算符
Point operator+(const Point& other) const {
return Point(x + other.x, y + other.y);
}
void print() const {
std::cout << "Point(" << x << ", " << y << ")" << std::endl;
}
};
🔹 使用方式:
Point p1(1, 2);
Point p2(3, 4);
Point p3 = p1 + p2;
p3.print(); // 输出: Point(4, 6)
🧪 七、完整示例代码(含所有知识点)
#include <iostream>
template <typename T>
struct Point {
T x;
T y;
explicit Point(T x_val = T(), T y_val = T()) : x(x_val), y(y_val) {}
~Point() {
std::cout << "Point destroyed!" << std::endl;
}
Point<T> operator+(const Point<T>& other) const {
return Point<T>(x + other.x, y + other.y);
}
void print() const {
std::cout << "Point(" << x << ", " << y << ")" << std::endl;
}
};
int main() {
Point<int> p1(1, 2);
Point<int> p2(3, 4);
Point<int> p3 = p1 + p2;
p3.print();
Point<std::string> pStr1("Hello", "C++");
Point<std::string> pStr2("World", "!");
Point<std::string> pStr3 = pStr1 + pStr2;
pStr3.print(); // 注意:字符串拼接需要 operator+ 支持
return 0;
}
🎯 总结图表
特性 | 关键词/方法 | 用途 |
---|---|---|
定义结构体 | struct |
创建自定义数据类型 |
构造函数 | T() |
初始化成员变量 |
析构函数 | ~T() |
清理资源 |
显式构造 | explicit |
禁止隐式转换 |
泛型结构 | template<typename T> |
支持多类型 |
运算符重载 | operator+ , operator== 等 |
自定义操作行为 |
📘 推荐练习题
- 实现一个
Fraction
(分数)结构体,包含分子和分母。 - 添加构造函数并重载
+
,-
,==
运算符。 - 使用
explicit
防止从整数隐式构造。 - 使用模板泛型支持
float
,double
,int
类型。
📚 参考资料 & 学习路径建议
主题 | 推荐学习顺序 |
---|---|
基础语法 | 变量、控制流、函数 |
OOP | 类、继承、多态 |
STL | vector、map、智能指针 |
高级特性 | 模板、lambda、移动语义 |
设计模式 | 单例、工厂、策略等 |
🧠 小贴士 💡
- 使用
std::unique_ptr
替代手动内存管理更安全。 - 对于频繁使用的类,考虑使用
move semantics
提高性能。 - 多用
const
表示不会修改对象状态的方法。 - 在大型项目中使用命名空间避免名称冲突。
7 条评论
-
admin SU @ 2025-6-2 22:02:52已修改
#include<iostream> using namespace std; struct Vector { int x; int y; // 重载+运算符 Vector operator+(const Vector& v) { Vector result; result.x = x + v.x; result.y = y + v.y; return result; } int operator*(const Vector& v) { return 999; } // 重载<<运算符 friend ostream& operator<<(ostream& os, const Vector& p) { os << "(" << p.x << ", " << p.y << ")"<<"!!!!"; return os; } }; int main() { // 使用 Vector v1 = {1, 2}; Vector v2 = {3, 4}; Vector v3 = v1 + v2; //cout<<v3.x<<" "<<v3.y<<endl; cout << v3 << endl; cout << v1*v2; return 0; }
friend
是 C++ 中的一个关键字,它用来让某个函数或类 成为一个类的“朋友”,也就是说:它可以访问这个类的私有(private)和受保护(protected)成员。
在你这段代码中:
friend ostream& operator<<(ostream& os, const Vector& p) { os << "(" << p.x << ", " << p.y << ")"<<"!!!!"; return os; }
这行
friend
的意思是:这个
operator<<
函数虽然是在Vector
结构体外面定义的普通函数(不是Vector
的成员函数),但它被声明为Vector
的友元(friend),所以它可以访问Vector
的私有成员变量(比如x
和y
)。
为什么需要 friend?
因为 C++ 中,默认情况下,类的成员是私有的(即使你写的是
struct
,默认也是 public,但是一旦用了private:
就不能访问了)。如果你把x
和y
设成私有的:struct Vector { private: int x; int y;
那么普通的外部函数就无法访问它们。但是加上
friend
后,这个operator<<
函数就可以直接访问这些私有成员了。
举个更简单的例子:
class Student { private: string name; public: Student(string n) : name(n) {} // 声明一个友元函数 friend void printName(Student s); }; // 友元函数定义 void printName(Student s) { cout << s.name; // 正常访问私有成员 } int main() { Student s("小明"); printName(s); // 输出:小明 return 0; }
在这个例子里,
printName
不是Student
的成员函数,但它可以访问Student
的私有成员name
,因为它被声明为友元。
总结一下
friend
的作用:类型 能否访问私有成员? 是否属于类的成员函数? 普通函数 ❌ 不能 ❌ 不是 成员函数 ✅ 可以 ✅ 是 友元函数 ❌ 不是
回到你的代码
你写的这一段很标准:
friend ostream& operator<<(ostream& os, const Vector& p) { os << "(" << p.x << ", " << p.y << ")"<<"!!!!"; return os; }
它的意思是:
- 我是一个友元函数。
- 我重载了
<<
运算符,使得你可以这样输出:
Vector v = {1, 2}; cout << v << endl;
- 输出结果会是:
(1, 2)!!!!
补充一点:运算符 * 为什么返回 999?
你在代码里写了:
int operator*(const Vector& v) { return 999; }
这其实是重载了
*
运算符,但是你没有真正做向量点乘或者其他操作,只是返回了一个固定值999
,所以:cout << v1*v2; // 输出 999
如果你想实现真正的向量点积,应该改成:
int operator*(const Vector& v) { return x * v.x + y * v.y; }
那这样的话,
v1 * v2
就是(1*3)+(2*4)=11
,而不是999
。
✅ 如果你是刚开始学 C++,建议记住:
friend
是让外部函数或类访问私有成员的一种方式。- 常用于重载像
<<
、>>
这样的运算符。 - 使用要谨慎,避免滥用,否则会破坏封装性。
如需我帮你画图解释,也可以告诉我 😊 在 C++ 里,
friend
是一个关键字,其作用是让函数或者类能够访问另一个类的私有成员与保护成员,即便它并非这个类的成员。下面结合你给出的代码来详细剖析friend
的用法:friend ostream& operator<<(ostream& os, const Vector& p) { os << "(" << p.x << ", " << p.y << ")" << "!!!!"; return os; }
这里的
friend
有以下作用:- 访问私有成员:在
Vector
类里,x
和y
都属于公有成员,所以其实不使用friend
也能够访问。不过,要是x
和y
是私有成员,那么就必须借助friend
来让operator<<
函数获得访问权限。 - 非成员函数:
operator<<
并非Vector
类的成员函数,它实际上是一个全局函数。friend
让这个全局函数能够访问Vector
类的私有成员。 - 运算符重载:在重载
<<
运算符时,一般会把它定义为非成员函数,这样才能保证运算符的左侧可以是流对象(像ostream
)。
为什么要使用
friend
来重载<<
运算符呢?- 要是把
operator<<
定义成成员函数,它就会默认把Vector
对象作为左侧操作数,这显然不符合我们的使用习惯。 - 而将其定义为非成员函数,同时使用
friend
关键字,就能让运算符左侧是流对象,右侧是Vector
对象,符合正常的使用方式。
其他需要留意的要点:
friend
这种访问权限是单向的,并且不会被继承。- 过度运用
friend
会破坏类的封装性,所以要谨慎使用。 - 在你的代码中,
x
和y
是公有成员,此时friend
其实不是必需的。不过,按照惯例,重载<<
运算符时通常会把它定义为friend
函数。
补充示例:
下面展示一个
x
和y
为私有成员的例子:struct Vector { private: int x; int y; public: Vector(int x = 0, int y = 0) : x(x), y(y) {} // 重载<<运算符,需要friend才能访问私有成员 friend ostream& operator<<(ostream& os, const Vector& p) { os << "(" << p.x << ", " << p.y << ")"; return os; } };
总结:
在你的代码里,
friend
关键字使得operator<<
函数能够访问Vector
类的私有成员(如果有的话),同时保证了运算符重载的正确调用形式。 -
2025-6-2 21:54:01@
#include<iostream> using namespace std; struct Vector { int x; int y; // 重载+运算符 Vector operator+(const Vector& v) { Vector result; result.x = x + v.x; result.y = y + v.y; return result; } int operator*(const Vector& v) { return 999; } }; int main() { // 使用 Vector v1 = {1, 2}; Vector v2 = {3, 4}; Vector v3 = v1 + v2; cout<<v3.x<<" "<<v3.y<<endl; cout<<v1*v2; return 0; }
-
2025-6-2 21:43:41@
#include<iostream> using namespace std; struct Point { int x, y; //Point(int val) : x(val), y(val) {} explicit Point(int val) : x(val), y(val) {} void print(){ cout<<x<<" "<<y<<endl; } }; void printPoint(Point p) { p.print(); } int main() { //printPoint(5); // 编译器会自动将 5 转换为 Point(5) //Point t1(5); //Point (5);//匿名结构体 printPoint(Point(5)); // 正确 return 0; }
-
2025-6-2 21:41:23@
#include<iostream> using namespace std; struct Point { int x, y; Point(int val) : x(val), y(val) {} void print(){ cout<<x<<" "<<y<<endl; } }; void printPoint(Point p) { p.print(); } int main() { printPoint(5); // 编译器会自动将 5 转换为 Point(5) return 0; }
-
2025-6-2 21:36:48@
explicit
这个英文单词的中文读音为 “ɪkˈsplɪsɪt”(国际音标),用汉字近似发音可以读作 “衣克丝普里西特”(注意这只是近似,准确发音建议参考音标)。在 C++ 中,
explicit
是一个关键字,用于修饰构造函数,防止隐式类型转换。例如:class MyClass { public: explicit MyClass(int x) { ... } // 显式构造函数,禁止隐式转换 }; // 以下代码会报错,因为禁止隐式转换 MyClass obj = 42; // 错误!不能隐式转换 // 必须显式构造 MyClass obj(42); // 正确 MyClass obj = MyClass(42); // 正确
总结:
explicit
的中文读音是 “衣克丝普里西特”,在 C++ 中用于强制显式构造对象。 -
2025-6-2 21:35:09@
#include<iostream> using namespace std; struct Data { int* buffer; Data(int size) { buffer = new int[size]; cout<<"11111"<<endl; } ~Data() { delete[] buffer; // 释放动态分配的内存 cout<<"333333"<<endl; } void print(){ cout<<"222222"<<endl; } }; int main() { Data t1(10); t1.print(); cout<<"main"<<endl; return 0; }
-
2025-5-29 11:51:57@
C++ 结构体与高级特性教程
1. 结构体(Struct)
定义:结构体是一种用户自定义的数据类型,允许将不同类型的数据项组合在一起。
语法:
struct 结构体名称 { // 成员变量 数据类型 变量名; // 成员函数 返回类型 函数名(参数列表) { /* 函数体 */ } };
示例:
struct Point { int x; // 成员变量:x坐标 int y; // 成员变量:y坐标 // 成员函数:计算到原点的距离 double distance() { return sqrt(x * x + y * y); } };
使用:
Point p; // 创建结构体变量 p.x = 3; // 访问成员变量 p.y = 4; cout << p.distance(); // 调用成员函数
2. 构造函数(Constructor)
定义:构造函数是一种特殊的成员函数,用于初始化对象的状态。
特点:
- 函数名与结构体名相同
- 没有返回类型
- 创建对象时自动调用
示例:
struct Rectangle { int width; int height; // 默认构造函数 Rectangle() { width = 0; height = 0; } // 带参数的构造函数 Rectangle(int w, int h) { width = w; height = h; } // 计算面积 int area() { return width * height; } };
使用:
Rectangle r1; // 调用默认构造函数 Rectangle r2(5, 10); // 调用带参数的构造函数
3. 释放函数(析构函数 Destructor)
定义:析构函数用于在对象销毁时释放资源。
特点:
- 函数名是结构体名前加
~
- 没有参数和返回值
- 对象销毁时自动调用
示例:
struct FileHandler { FILE* file; // 构造函数 FileHandler(const char* filename) { file = fopen(filename, "r"); if (!file) { cout << "文件打开失败" << endl; } } // 析构函数 ~FileHandler() { if (file) { fclose(file); // 释放资源 cout << "文件已关闭" << endl; } } };
使用:
{ FileHandler fh("data.txt"); // 使用文件... } // 作用域结束,fh对象销毁,自动调用析构函数
4. explicit 关键字
作用:防止单参数构造函数的隐式类型转换。
示例:
struct Distance { double meters; // 带explicit的构造函数 explicit Distance(double m) : meters(m) {} // 比较函数 bool isGreaterThan(Distance d) { return meters > d.meters; } }; // 使用 Distance d1(10.5); // Distance d2 = 5.0; // 错误!explicit禁止隐式转换 Distance d2(5.0); // 正确
5. 结构体模板(Template)
定义:允许创建通用的结构体,支持多种数据类型。
语法:
template <typename T> struct 结构体名称 { T 变量名; // ... };
示例:
template <typename T> struct Pair { T first; T second; // 构造函数 Pair(T a, T b) : first(a), second(b) {} // 返回较大值 T max() { return (first > second) ? first : second; } };
使用:
Pair<int> p1(10, 20); // 整数对 Pair<double> p2(3.14, 2.71); // 双精度浮点对 cout << p1.max() << endl; // 输出: 20
6. 重载运算符(Operator Overloading)
定义:允许重新定义运算符的行为,使其适用于自定义类型。
语法:
返回类型 operator运算符(参数列表) { /* 函数体 */ }
示例1:重载
+
运算符struct Vector { int x; int y; // 重载+运算符 Vector operator+(const Vector& v) { Vector result; result.x = x + v.x; result.y = y + v.y; return result; } }; // 使用 Vector v1 = {1, 2}; Vector v2 = {3, 4}; Vector v3 = v1 + v2; // 调用重载的+运算符
示例2:重载
<<
运算符(用于输出)struct Point { int x; int y; // 重载<<运算符 friend ostream& operator<<(ostream& os, const Point& p) { os << "(" << p.x << ", " << p.y << ")"; return os; } }; // 使用 Point p = {5, 10}; cout << p << endl; // 输出: (5, 10)
综合示例
下面是一个包含上述所有特性的综合示例:
#include <iostream> using namespace std; // 结构体模板 template <typename T> struct Complex { T real; // 实部 T imag; // 虚部 // 构造函数 explicit Complex(T r = 0, T i = 0) : real(r), imag(i) {} // 析构函数 ~Complex() { // 释放资源(如果有动态分配的内存) } // 重载+运算符 Complex operator+(const Complex& c) { return Complex(real + c.real, imag + c.imag); } // 重载<<运算符(友元函数) friend ostream& operator<<(ostream& os, const Complex& c) { os << c.real; if (c.imag >= 0) os << "+"; os << c.imag << "i"; return os; } }; int main() { // 创建复数对象 Complex<double> c1(3.5, 2.1); Complex<double> c2(1.2, -4.3); // 使用重载的+运算符 Complex<double> c3 = c1 + c2; // 使用重载的<<运算符输出 cout << "c1 = " << c1 << endl; cout << "c2 = " << c2 << endl; cout << "c1 + c2 = " << c3 << endl; return 0; }
输出结果:
c1 = 3.5+2.1i c2 = 1.2-4.3i c1 + c2 = 4.7-2.2i
总结
概念 作用 结构体 组合不同类型的数据项为一个整体 构造函数 初始化对象状态 析构函数 释放对象占用的资源 explicit 防止单参数构造函数的隐式类型转换 结构体模板 创建通用结构体,支持多种数据类型 重载运算符 自定义运算符对结构体的行为 通过这些特性,C++提供了强大的机制来创建灵活、高效的自定义数据类型。
- 1