• 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;
    }
};

🔹 structclass 的区别在于默认访问权限:

  • 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== 自定义操作行为

📘 推荐练习题

  1. 实现一个 Fraction(分数)结构体,包含分子和分母。
  2. 添加构造函数并重载 +, -, == 运算符。
  3. 使用 explicit 防止从整数隐式构造。
  4. 使用模板泛型支持 float, double, int 类型。

📚 参考资料 & 学习路径建议

主题 推荐学习顺序
基础语法 变量、控制流、函数
OOP 类、继承、多态
STL vector、map、智能指针
高级特性 模板、lambda、移动语义
设计模式 单例、工厂、策略等

🧠 小贴士 💡

  • 使用 std::unique_ptr 替代手动内存管理更安全。
  • 对于频繁使用的类,考虑使用 move semantics 提高性能。
  • 多用 const 表示不会修改对象状态的方法。
  • 在大型项目中使用命名空间避免名称冲突。

7 条评论

  • @ 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 的私有成员变量(比如 xy)。


    为什么需要 friend?

    因为 C++ 中,默认情况下,类的成员是私有的(即使你写的是 struct,默认也是 public,但是一旦用了 private: 就不能访问了)。如果你把 xy 设成私有的:

    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 有以下作用:

    1. 访问私有成员:在 Vector 类里,xy 都属于公有成员,所以其实不使用 friend 也能够访问。不过,要是 xy 是私有成员,那么就必须借助 friend 来让 operator<< 函数获得访问权限。
    2. 非成员函数operator<< 并非 Vector 类的成员函数,它实际上是一个全局函数。friend 让这个全局函数能够访问 Vector 类的私有成员。
    3. 运算符重载:在重载 << 运算符时,一般会把它定义为非成员函数,这样才能保证运算符的左侧可以是流对象(像 ostream)。

    为什么要使用 friend 来重载 << 运算符呢?

    • 要是把 operator<< 定义成成员函数,它就会默认把 Vector 对象作为左侧操作数,这显然不符合我们的使用习惯。
    • 而将其定义为非成员函数,同时使用 friend 关键字,就能让运算符左侧是流对象,右侧是 Vector 对象,符合正常的使用方式。

    其他需要留意的要点:

    • friend 这种访问权限是单向的,并且不会被继承。
    • 过度运用 friend 会破坏类的封装性,所以要谨慎使用。
    • 在你的代码中,xy 是公有成员,此时 friend 其实不是必需的。不过,按照惯例,重载 << 运算符时通常会把它定义为 friend 函数。

    补充示例:

    下面展示一个 xy 为私有成员的例子:

    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