当前位置: 首页 > news >正文

烦了。。。。。

#include <iostream>
#include <string>
using namespace std;class Student {
private:string name;  // 姓名int age;      // 年龄
public:// 1. 默认构造函数Student() : name("默认学生"), age(0) {cout << "调用默认构造函数" << endl;}// 2. 带参构造函数(支持隐式类型转换)Student(const string& n, int a = 0) : name(n), age(a) {cout << "调用带参构造函数: " << n << ",年龄: " << a << endl;}// 3. 拷贝构造函数Student(const Student& other) : name(other.name), age(other.age) {cout << "调用拷贝构造函数,从 " << other.name << endl;}// 4. 委托构造函数(C++11+)Student(int a) : Student("匿名学生", a) {cout << "调用委托构造函数" << endl;}// 公有的获取 name 的方法string getName() const {return name;}
};// 测试隐式转换的函数
void func(Student s) {cout << "函数参数隐式转换为: " << s.getName() << endl;
}int main() {// 隐式调用示例cout << "\n隐式调用示例:\n";Student s1("张三");          // 直接调用带参构造函数Student s2 = 20;             // 隐式调用 Student(int a)func(Student("李四"));       // 显式构造 Student 对象,明确调用带参构造函数// 显式调用示例cout << "\n显式调用示例:\n";Student s3;                  // 默认构造Student s4("王五", 22);      // 带参构造Student s5(s4);              // 拷贝构造Student s6 = Student("赵六", 25); // 显式拷贝初始化return 0;
}

一、封装的实现(对应文档知识点 1)

代码中的封装体现

cpp

class Student {
private:string name;  // 姓名int age;      // 年龄
public:// 构造函数和成员函数(接口)string getName() const { return name; } // 公开访问接口
};

  • 私有成员隐藏细节name 和 age 被声明为 private,外部无法直接访问,只能通过公有成员函数(如 getName())操作,符合文档中 “隐藏对象内部细节” 的封装目的。
  • 数据与方法结合:通过构造函数初始化数据,通过成员函数暴露操作接口,实现了文档中 “基本数据类型 + 操作函数” 的封装手段。

二、构造函数的类型与特点(对应文档知识点 2)

1. 默认构造函数(无参构造)

cpp

Student() : name("默认学生"), age(0) {cout << "调用默认构造函数" << endl;
}

  • 特点
    • 无参数,函数名与类名相同,无返回值类型(非 void)。
    • 使用初始化列表 : name("默认学生"), age(0) 初始化成员变量,对应文档中 “初始化列表为成员申请栈空间” 的规则。
  • 调用场景

    cpp

    Student s3; // 显式调用默认构造函数
    
2. 带参构造函数(支持隐式转换)

cpp

Student(const string& n, int a = 0) : name(n), age(a) {cout << "调用带参构造函数: " << n << ",年龄: " << a << endl;
}

  • 特点
    • 形参为 string 和 int,允许参数默认值(int a = 0)。
    • 支持隐式调用

      cpp

      Student s1("张三"); // 等价于 Student("张三", 0),隐式传递默认参数
      func("李四"); // 隐式转换:const char* → string → Student对象(需警惕歧义)
      
    • 对应文档中 “构造函数允许重载,形参类型不同” 的规则。
3. 拷贝构造函数

cpp

Student(const Student& other) : name(other.name), age(other.age) {cout << "调用拷贝构造函数,从 " << other.name << endl;
}

  • 特点
    • 参数为类对象的引用const Student&),用于通过已存在对象创建新对象。
    • 深拷贝成员变量,避免浅拷贝导致的资源泄漏。
  • 调用场景

    cpp

    Student s5(s4); // 直接初始化,调用拷贝构造函数
    Student s6 = Student("赵六", 25); // 显式拷贝初始化
    
4. 委托构造函数(C++11+,对应文档扩展)

cpp

Student(int a) : Student("匿名学生", a) {cout << "调用委托构造函数" << endl;
}

  • 特点
    • 通过 : Student("匿名学生", a) 委托调用带参构造函数,复用初始化逻辑,减少代码重复。
    • 调用顺序:先执行被委托的构造函数,再执行当前函数体。
  • 隐式调用示例

    cpp

    Student s2 = 20; // 隐式调用 Student(int a),委托为 Student("匿名学生", 20)
    

三、构造函数的调用形式(对应文档 2.1 特点 3)

1. 直接初始化(无隐式转换)

cpp

Student s1("张三"); // 等价于 Student s1 = Student("张三");
Student s4("王五", 22); // 显式传递多个参数

  • 直接通过括号传递参数,明确调用对应构造函数,无歧义。
2. 隐式调用(需注意 explicit

cpp

Student s2 = 20; // 隐式调用 Student(int a)
// 若构造函数声明为 explicit Student(int a),则此行会编译报错

  • 风险:隐式转换可能导致意外的类型转换(如 int → Student),可通过 explicit 关键字禁止(文档提及)。
  • 显式规避歧义

    cpp

    func(Student("李四")); // 显式构造对象,避免匹配错误构造函数
    
3. 拷贝初始化

cpp

Student s6 = Student("赵六", 25); // 显式调用带参构造函数,再拷贝初始化

  • 等价于 Student s6("赵六", 25);,但会多一次拷贝构造(C++ 优化后可能省略)。

四、初始化列表的作用(对应文档 2.2)

cpp

Student() : name("默认学生"), age(0) { ... }
Student(const string& n, int a) : name(n), age(a) { ... }

  • 作用
    1. 为成员变量申请栈空间并初始化:直接对 name 和 age 赋初值,比在函数体中赋值更高效。
    2. 初始化常量成员或引用成员(代码中未体现,但文档提到初始化列表的必要性)。
  • 注意:初始化列表的参数必须与成员变量名一一对应,顺序不影响编译,但建议与声明顺序一致以提高可读性。

五、编译器行为与无参构造函数(对应文档 2.1 特点 5)

  • 自动生成无参构造函数的条件
    • 若类中未定义任何构造函数,编译器会自动生成一个空的无参构造函数。
    • 若已定义任意构造函数(如代码中的带参构造、拷贝构造等),编译器不再自动生成无参构造函数,需手动定义:

      cpp

      Student() { ... } // 手动定义默认构造函数,否则无法调用 Student s3;
      

六、代码中的潜在问题与优化(结合文档扩展)

  1. 隐式转换的歧义
    • 当存在多个单参数构造函数时(如 Student(int) 和 Student(string)),隐式调用可能引发歧义,建议用 explicit 修饰单参数构造函数:

      cpp

      explicit Student(int a) : Student("匿名学生", a) { ... } // 禁止隐式转换
      
  2. 拷贝构造函数的必要性
    • 若类中包含动态分配资源(如 new 分配的内存),需自定义拷贝构造函数实现深拷贝,避免默认浅拷贝导致的悬挂指针。

总结:代码与文档知识点的映射

文档知识点代码实现示例
封装:隐藏私有成员,公开接口nameage 为 private,通过 getName() 访问
构造函数无返回值所有构造函数均无 void 或其他返回值类型
构造函数名与类名相同Student()Student(const string&) 等函数名均为 Student
隐式调用与 explicitStudent s2 = 20; 隐式调用 Student(int),可添加 explicit 禁止
构造函数重载存在默认、带参、拷贝、委托四种构造函数,形参类型不同
初始化列表所有构造函数均使用初始化列表初始化成员变量
无参构造函数手动定义显式定义 Student(),避免编译器不生成导致的错误

通过以上分析,可以清晰看到代码如何体现文档中关于封装和构造函数的核心概念,建议结合编译错误和调试输出进一步理解构造函数的调用顺序和隐式转换规则。

以下是三个不同类的构造函数示例代码,分别演示不同的构造函数特性(默认构造、带参构造、拷贝构造、委托构造、移动构造等),结合初始化列表和隐式调用等知识点:

示例 1:Point 类(坐标点)

cpp

运行

#include <iostream>
using namespace std;class Point {
private:int x;int y;
public:// 1. 默认构造函数Point() : x(0), y(0) {cout << "调用Point默认构造函数,坐标(0, 0)" << endl;}// 2. 带参构造函数(支持默认参数)Point(int a, int b = 0) : x(a), y(b) {cout << "调用Point带参构造函数,坐标(" << a << ", " << b << ")" << endl;}// 3. 拷贝构造函数Point(const Point& p) : x(p.x), y(p.y) {cout << "调用Point拷贝构造函数,复制坐标(" << p.x << ", " << p.y << ")" << endl;}// 4. 委托构造函数(利用带参构造初始化x=0)Point(int a) : Point(0, a) { // 委托给Point(int, int)cout << "调用Point委托构造函数,y=" << a << endl;}
};int main() {cout << "\n--- Point类构造函数示例 ---" << endl;Point p1;              // 默认构造Point p2(3, 4);        // 显式带参构造Point p3 = p2;         // 拷贝构造Point p4 = 5;          // 隐式调用委托构造函数 Point(5) → 委托为Point(0,5)Point p5 = Point(6, 7); // 显式拷贝初始化return 0;
}

输出结果

plaintext

--- Point类构造函数示例 ---
调用Point默认构造函数,坐标(0, 0)
调用Point带参构造函数,坐标(3, 4)
调用Point拷贝构造函数,复制坐标(3, 4)
调用Point带参构造函数,坐标(0, 5)
调用Point委托构造函数,y=5
调用Point带参构造函数,坐标(6, 7)

示例 2:Circle 类(圆,含 explicit 防止隐式转换)

cpp

运行

#include <iostream>
using namespace std;class Circle {
private:double radius;double area;
public:// 1. 默认构造函数(半径0,面积0)Circle() : radius(0.0), area(0.0) {cout << "调用Circle默认构造函数,半径0" << endl;}// 2. 带参构造函数(显式禁止隐式转换)explicit Circle(double r) : radius(r), area(3.14159 * r * r) {cout << "调用Circle显式构造函数,半径" << r << ",面积" << area << endl;}// 3. 拷贝构造函数(深拷贝)Circle(const Circle& c) : radius(c.radius), area(c.area) {cout << "调用Circle拷贝构造函数,复制半径" << c.radius << endl;}// 4. 委托构造函数(利用double构造函数初始化半径1)Circle() : Circle(1.0) { // 委托给Circle(double r)cout << "调用Circle委托构造函数,默认半径1" << endl;}
};int main() {cout << "\n--- Circle类构造函数示例 ---" << endl;Circle c1;              // 调用委托构造 → 调用Circle(1.0)// Circle c2 = 2.5;       // 报错!因构造函数被explicit修饰,禁止隐式转换Circle c2(2.5);         // 显式调用Circle(double)Circle c3 = c2;         // 拷贝构造// Circle c4 = {3.0};     // 报错!explicit禁止列表初始化隐式转换return 0;
}

关键说明

  • explicit 关键字禁止隐式转换,如 Circle c2 = 2.5; 会编译报错,必须显式调用 Circle c2(2.5);
  • 委托构造函数 Circle() : Circle(1.0) 先调用 Circle(double) 构造函数,再执行当前函数体。

示例 3:Employee 类(员工,含动态内存与移动构造)

cpp

运行

#include <iostream>
#include <string>
using namespace std;class Employee {
private:string name;int* age; // 动态分配内存示例
public:// 1. 默认构造函数(动态初始化)Employee() : name("无名氏"), age(new int(0)) {cout << "调用Employee默认构造函数,年龄0" << endl;}// 2. 带参构造函数(初始化列表初始化动态内存)Employee(string n, int a) : name(n), age(new int(a)) {cout << "调用Employee带参构造函数,姓名" << n << ",年龄" << a << endl;}// 3. 拷贝构造函数(深拷贝动态内存)Employee(const Employee& emp) : name(emp.name), age(new int(*emp.age)) {cout << "调用Employee拷贝构造函数,复制姓名" << emp.name << endl;}// 4. 移动构造函数(转移资源所有权)Employee(Employee&& emp) noexcept : name(move(emp.name)), age(emp.age) {emp.age = nullptr; // 置空原指针避免重复释放cout << "调用Employee移动构造函数,转移资源" << endl;}// 析构函数(释放动态内存)~Employee() {if (age) delete age;cout << "调用Employee析构函数,释放年龄内存" << endl;}
};int main() {cout << "\n--- Employee类构造函数示例 ---" << endl;Employee e1("张三", 25);        // 带参构造Employee e2 = std::move(e1);     // 移动构造(转移e1的资源)Employee e3(e2);                 // 拷贝构造(深拷贝e2的资源)return 0;
}

关键说明

  • 动态内存管理:通过 new 在堆上分配 age 内存,避免栈内存的局限性。
  • 深拷贝:拷贝构造函数中使用 new int(*emp.age) 重新分配内存,防止多个对象指向同一内存地址。
  • 移动构造函数:通过 std::move 转移资源所有权,避免深拷贝的性能开销,适用于临时对象(如函数返回值)的初始化。

总结:构造函数核心知识点应用

  1. 初始化列表:所有构造函数均使用初始化列表直接初始化成员变量,比在函数体中赋值更高效。
  2. 隐式调用与 explicit:示例 2 通过 explicit 禁止单参数构造函数的隐式转换,避免意外类型转换。
  3. 资源管理:示例 3 通过动态内存和移动构造函数,展示构造函数在资源分配与转移中的作用。
  4. 委托构造:示例 1 和示例 2 通过委托构造函数复用其他构造函数的逻辑,减少代码重复。

通过不同类的构造函数设计,可以灵活应对数据初始化、类型安全、性能优化等场景。

相关文章:

  • 语法--05--句子成分
  • 6个月Python学习计划 Day 1
  • 【重点案例1】案例1-3流水灯
  • Socket套接字概述
  • 可信计算是什么?可信逻辑:计算系统安全的形式化分析框架
  • 火语言UI组件--控件属性操作
  • 机器学习第二十三讲:CNN → 用放大镜局部观察图片特征层层传递
  • 第五章:异步幻境 · 时间与数据的秘密
  • 探秘 OneCode 双向转换引擎:数据双向流动的核心驱动力
  • 精益数据分析(78/126):问题-解决方案画布的实战应用与黏性阶段关键总结
  • ObservableCollection序列化,和监听链表内元素变化
  • 【Java】—— 常见的排序算法
  • Modelsim的入门使用和Verilog编写
  • 在 Ubuntu 24.04 LTS 上 Docker 部署 DB-GPT
  • 汇舟问卷:国外问卷调查如何闭坑
  • 【RocketMQ 生产者和消费者】- 生产者启动源码-启动流程(1)
  • 选新手机的参考:CPU型号、内存、外存、屏幕、摄像头以及电池等。
  • 如何测试JWT的安全性:全面防御JSON Web Token的安全漏洞
  • AI Agent开发第73课-预训练qwen3-如何加入自己的语料
  • ElasticSearch操作
  • html国外网站源码/百度搜索引擎入口登录
  • 用asp做的网站打开页面很慢/免费创建属于自己的网站
  • 莱芜可靠的网站建设/营销案例100例小故事及感悟
  • phpcms做网站页面开发/怎么分析一个网站seo
  • wordpress in排序/西安seo报价
  • 找别人做网站的注意事项/企业品牌推广