C++基础知识学习记录—构造函数

news/2025/2/13 1:47:07/

1、构造函数(constructor)

作用:用于创建对象时给属性值进行初始化

构造函数是一个特殊的函数:

1、构造函数与类同名

2、如果没有显式给出构造函数,编译器会给出默认的构造函数(参数为空,并且函数体也为空),并没有实际操作,如果给出任意的构造函数,系统默认的构造函数就不存在了。

3、构造函数是在创建对象的时候,自动调用的。

4、有返回值,但是不写返回值类型,也不可以写void

 构造函数分为有参构造函数和无参构造函数,也就是说构造函数可以重载

有参的构造函数的形参,也支持默认参数

但函数重载和参数默认值不能同时使用,否则会出现错误 

#include <iostream>
#include <string>using namespace std;class Goods
{
private:string name;string color;double price;public:/*编译器默认的构造函数   参数为空,函数体也为空goods(){}*///无参构造函数Goods(){name="上衣";color="白色";price = 119.9;}//有参构造函数  构造函数可以重载Goods(string n,string c,double p){name=n;color=c;price = p;}void show(){cout << color << "的" << name << "单价是" << price << endl;}
};
int main()
{Goods g1;//调用无参构造函数g1.show();Goods g2("裤子","黑色",99.9);//调用有参构造函数g2.show();return 0;
}
    有参构造函数 形参支持默认参数Goods(string n="鞋子",string c="酒红色",double p=298.9){name=n;color=c;price = p;}

构造初始化列表

在现阶段,构造初始化列表是一种更简单的给成员变量赋予初始值的写法

 如上面的构造函数可以简写为

    Goods():name("上衣"),color("白色"),price(119.9){  }Goods(string name,string color,double price):name(name),color(color),price(price){  }

2、拷贝构造函数

当程序员不手写拷贝构造函数时,编译器会自动添加一个拷贝构造函数,用于实现对象的拷贝创建。

拷贝构造函数的特点:

1、拷贝构造函数与构造函数构成重载

2、如果不显式地写出拷贝构造函数,编译器会给出默认的拷贝构造函数,完成对象之间的值复制,如果显式地写出拷贝构造函数,编译器就不会提供默认的拷贝构造函数。

拷贝构造函数的形式:

1、与类同名

2、参数是对象的引用或者是const修饰对象的引用

3、拷贝构造函数是在拷贝对象时,自动调用

对象之间是相互独立的,对象之间的属性也是相互独立的。

#include <iostream>
#include <string>using namespace std;class Phone
{
private:string brand;//brand:品牌string model;double price;
public:Phone(string brand,string model,double price):brand(brand),model(model),price(price){   }//编译器默认的构造拷贝函数Phone(const Phone& iphone){brand=iphone.brand;model=iphone.model;price=iphone.price;}void show(){cout << "品牌:" << brand << " 型号:" << model;cout << " 价格:" << price << endl;}
};
int main()
{Phone P1("红米","K80Pro",2699.9);P1.show();Phone* P2 = new Phone("华为","mate60",5699.9);P2->show();delete P2;P2=NULL;Phone P3(P1);//面向对象的前提:每个对象单独持有一份自己的成员变量P3.show();return 0;
}

1、浅拷贝

编译器默认给出的拷贝构造函数,完成的就是浅拷贝,会完成对象之间简单的值复制。如果对象的属性有指针类型时,也只会简单的地址值复制,这两个对象的指针保存同一块地址,指向了同一块内存,破坏了对象之间的独立性,此时需要手写深拷贝。

#include <iostream>
#include <string>
#include <string.h>
using namespace std;class Phone
{
private:char* brand;
public:Phone(char* brand):brand(brand){  }//构造拷贝函数,如不自定义编译器有默认的,可以直接拿来用//Phone(const Phone& Ph)//{//    brand=Ph.brand;//}void show(){cout << brand << endl;}char* get_brand(){return brand;}
};
int main()
{char ch[20]="Redmi";Phone P1(ch);Phone P2(P1);P1.show();P2.show();strcpy(ch,"xiaomi");P1.show();P2.show();strcpy(P1.get_brand(),"iPhone");P1.show();P2.show();strcpy(P2.get_brand(),"huawei");P1.show();P2.show();return 0;
}

上述代码,创建了一个手机类,两个手机类对象,P1和P2。直接修改字符串ch,P1和P2的型号 都会跟着改变;修改P1的型号,P2的型号也会变化;修改P2的型号,P1的型号也会改变。

这就是浅拷贝的隐患,当成员变量出现指针类型时,默认的拷贝构造函数会导致两个对象的成员变量指向同一处,不符合面向对象的设计规范,违背了对象的独立性

2、深拷贝

当对象属性有指针类型时,对象指针变量需要指向自己独立的区域,拷贝内容代替拷贝地址

#include <iostream>
#include <string>
#include <string.h>
using namespace std;class Phone
{
private:char* brand;
public:Phone(char* bra){brand = new char[20];strcpy(brand,bra);}Phone(const Phone& Ph){brand = new char[20];strcpy(brand,Ph.brand);}void show(){cout << brand << endl;}char* get_brand(){return brand;}
};int main()
{char ch[20]="Redmi";Phone P1(ch);Phone P2(P1);P1.show();P2.show();cout << endl;strcpy(ch,"xiaomi");P1.show();cout << "*********" << endl;P2.show();cout << endl;strcpy(P1.get_brand(),"iPhone");P1.show();cout << "*********" << endl;P2.show();cout << endl;strcpy(P2.get_brand(),"huawei");P1.show();cout << "*********" << endl;P2.show();return 0;
}

 上述代码是深拷贝,结果就是:直接修改字符串ch,P1和P2的型号都不会变化;修改P1的型号,P2的型号不会变化;修改P2的型号,P1的型号不会改变。

3、隐式调用构造函数

等号赋值时,等号左侧是对象类型,右侧恰好是对象构造函数所需要的类型,这时就会把右侧值传入到构造函数中,相当于隐式调用构造函数。在编码过程中,可能会不小心,隐式触发调用构造函数,造成错误,这时可以用explicit关键字屏蔽隐式构造函数调用。

#include <iostream>using namespace std;class Value
{
private:int val;
public:Value(int v)//如果加上explicit 关键字:val(v){cout << "构造函数成功" << endl;}int get_val(){return val;}
};int main()
{// 隐式调用构造函数Value v1 = 888;//如果构造函数加上explicit 关键字,隐式调用构造函数会失败cout << "1 " << v1.get_val()  << endl;// 隐式调用拷贝构造函数Value v2 = v1;cout << "2 " << v2.get_val() << endl;return 0;
}

4、析构函数

构造函数

析构函数

不需要用户调用,创建对象时自动调用

当对象销毁时,自动调用

函数名是类名

函数名是 ~类名

构造函数可以重载

析构函数没有参数,不能重载

用于创建对象时,初始化对象属性

用于销毁对象时,释放资源

有返回值但是不写,void也不行。返回值是新创建的对象

没有返回值

析构函数:对象销毁前做善后清理工作。在对象销毁时,之前为成员变量开辟的内存空间需要进行释放。

形式:~类名(){ }

析构函数的特点:

1、函数名为~类名,因为没有参数,所以不能重载

2、不显式给出析构函数,会有默认的析构函数,函数体为空。给出析构函数,编译器就不在提供默认析构函数

3、对象销毁时,自动调用 

#include <iostream>using namespace std;
class Test{
private:string name;
public://构造函数Test(string n):name(n){}//析构函数~Test(){cout << name << " 的析构函数调用了" << endl;}
};
int main()
{Test t1("admin");{//局部代码块Test t2("lisi");}Test *t3=new Test("zhangsan");delete t3;t3=NULL;cout << "主函数执行完毕" << endl;return 0;
}

 


http://www.ppmy.cn/news/1571575.html

相关文章

Android studio怎么创建assets目录

在Android Studio中创建assets文件夹是一个简单的步骤&#xff0c;通常用于存储不需要编译的资源文件&#xff0c;如文本文件、图片、音频等 main文件夹&#xff0c;右键new->folder-assets folder

22.3、IIS安全分析与增强

目录 IIS安全威胁分析iis安全机制iis安全增强 IIS安全威胁分析 iis是微软公司的Web服务软件&#xff0c;主要提供网页服务&#xff0c;除此之外还可以提供其他服务&#xff0c;第一个最主要的是网页服务&#xff0c;第二个是SMTP邮件服务&#xff0c;第三个是FTP文件传输服务。…

DeepSeek-R1技术革命:用强化学习重塑大语言模型的推理能力

引言&#xff1a;低成本高性能的AI新范式 在2025年1月&#xff0c;中国AI公司DeepSeek发布了两个标志性模型——DeepSeek-R1-Zero与DeepSeek-R1&#xff0c;以仅600万美元的训练成本实现了与OpenAI O1系列&#xff08;开发成本约5亿美元&#xff09;相当的推理性能&#xff0c…

集成方案 | Docusign + 纷享销客,自动化合同签署,加速业务增长!

本文将详细介绍 Docusign 与纷享销客的集成步骤及其效果&#xff0c;并通过实际应用场景来展示 Docusign 的强大集成能力&#xff0c;以证明 Docusign 集成功能的高效性和实用性。 在数字化转型过程中&#xff0c;企业依赖高效的 CRM 系统来优化业务流程和客户关系管理。纷享销…

c# OpenCvSharp 16位转8位图

通过OpenCvSharp&#xff0c;将16位图转8位图&#xff0c;代码如&#xff1a; public static Mat Convert16BitTo8Bit(Mat src16, double max, double min){if (src16.Depth() 0){//已经是8位了return src16;}Mat dst8 Mat.Zeros(src16.Rows, src16.Cols, MatType.CV_8UC1);i…

Anaconda Navigator 与 Conda:GUI 和 CLI 的对比与使用

1. 引言 Anaconda 提供了两种主要的管理工具&#xff1a; Anaconda Navigator&#xff08;GUI 界面&#xff09;Conda&#xff08;命令行工具 CLI&#xff09; 这两种工具各有优劣&#xff0c;适用于不同类型的用户。本文将详细介绍它们的功能、使用方法及对比分析&#xff…

【前端】【面试】ref与reactive的区别

ref 与 reactive 的区别笔记 一、概述 在 Vue 3 的组合式 API 中&#xff0c;ref 和 reactive 是两个非常重要的响应式工具&#xff0c;它们都用于创建响应式数据&#xff0c;但在使用方式、适用场景和内部实现上存在一些区别。 二、基本使用方式 1. ref ref 用于创建一个…

Ubuntu指令学习(个人记录、偶尔更新)

Ubuntu指令学习 0、一点常用指令列表一、Ubuntu下复制与移动&#xff0c;cp/mv二、Ubuntu下echo 与 重定向>,>>三、Ubuntu下chmod,用户权限四、Ubuntu下的tar打包&#xff0c;gzip压缩五、Ubuntu(22.04)下系统语言为中文&#xff0c;切换主目录文件名为英文。六、Ubun…