浅谈C++|构造.析构函数篇

news/2024/11/20 0:31:49/


一对象的初始化和处理

1.1构造函数和析构函数

C++拥有构造函数和析构函数,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器提供的构造函数和析构函数是空实现。

·构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

·析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

语法:

构造函数语法:类名(){}

  1.构造函数,没有返回值也不写void

  2.函数名称与类名相同

  3.构造函数可以有参数,因此可以发生重载

  4.程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次

析构函数语法:~类名(){}

  1.析构函数,没有返回值也不写void

  2.函数名称与类名相同,在称前加上符号

  3.析构函数不可以有参数,因此不可以发生重载

  4.程序在对象销毁前会自动调用析构,

代码: 

#include <iostream>
using namespace std;
class person {
public:person() {cout << "person 构造函数调用" << endl;}~person() {cout << "person 析构函数调用" << endl;}};
void func() {person a;
}
int main() {func();return 0;
}

 1.2构造函数的分类和调用

两种分类方式:

  按参数分为:有参构造和无参构造

  按类型分为:普通构造和拷贝构造

三种调用方式:

  括号法

  显示法

  隐式转换发

1.2.1构造函数分类

(1)有参和无参构造函数

代码:

#include <iostream>
using namespace std;
class person {
public:person() {cout << "person 无参构造函数调用" << endl;}person(int a) {cout << "person 有参构造函数调用" << endl;}~person() {cout << "person 析构函数调用" << endl;}};
void func() {person a(1);
}
int main() {func();return 0;
}

(2)普通和拷贝构造函数 

 代码:

#include <iostream>
using namespace std;
class person {
public:int age;person() {cout << "person的普通构造函数" << endl;}person(const person& p) {age = p.age;//可以将传入的人的所有属性,拷贝到神上cout << "person的拷贝构造函数" << endl;}
};
void func() {//1.括号法person p1;p1.age = 10;person p2(p1);cout << p2.age << endl;
}
int main() {func();return 0;
}

1.2.2构造函数的调用方式

括号法

显示法

隐式转换发

(1)括号法:

#include <iostream>
using namespace std;
class person {
public:int age;person() {cout << "person的普通构造函数" << endl;}person(int a) {age = a;cout << "person的普通构造函数" << endl;}person(const person& p) {age = p.age;//可以将传入的人的所有属性,拷贝到神上cout << "person的拷贝构造函数" << endl;}
};
void func() {//1.括号法person p1;       //默认p1.age = 10;person p2(20);   //有参person p3(p1);   //拷贝//2.
}
int main() {func();return 0;
}

注意: person p() 会被认为是函数声明,并不是调用默认构造

(2)显示法:

#include <iostream>
using namespace std;
class person {
public:int age;person() {cout << "person的普通构造函数" << endl;}person(int a) {age = a;cout << "person的普通构造函数" << endl;}person(const person& p) {age = p.age;//可以将传入的人的所有属性,拷贝到神上cout << "person的拷贝构造函数" << endl;}
};
void func() {//2.显示法person p1;       //默认p1.age = 10;person p2=person(20);   //有参person p3=person(p1);   //拷贝//2.
}
int main() {func();return 0;
}

1.person(20)称为匿名对象,当前行执行后系统会立即回收匿名对象

2.不要用拷贝构造函数初始化匿名对象,person(p3) ->person  p3;相当于重新定义一个p3,发生重定义错误。

(3) 隐式转换法:

#include <iostream>
using namespace std;
class person {
public:int age;person() {cout << "person的普通构造函数" << endl;}person(int a) {age = a;cout << "person的普通构造函数" << endl;}person(const person& p) {age = p.age;//可以将传入的人的所有属性,拷贝到神上cout << "person的拷贝构造函数" << endl;}
};
void func() {//3.隐式转换发person p1;       //默认person p2=10;    //相当于person p2=person(10);person p3 = p2;  //相当于person p3 = person(p2);
}
int main() {func();return 0;
}

1.3拷贝构造函数调用时机

1.使用一个已经创建完毕的对象来初始化一个新对象。

2.值传递的方式给函数参数传值

3.以值方式返回局部对象

 1.3.1旧对象创建新对象

代码:

#include <iostream>
using namespace std;
class person {
public:int a;int b;person() {cout << "person的无参构造函数" << endl;}person(int a1) {a = a1;cout << "person的有参构造函数" << endl;}person(const person &p) {a = p.a;cout << "person的拷贝构造函数" << endl;}~person() {cout << "person的析构函数" << endl;}
};
void fun() {person A(10);person B(A);cout << B.a << ' ' << B.b << endl;
}
int main() {fun();return 0;
}

 1.3.2值传递的方式给函数参数传值

作为函数值传递时,只会复制拷贝函数中已将定义要拷贝的变量,其余的即使已经外部定义了,只要拷贝函数中没有指明要拷贝,形参就不会拷贝。

#include <iostream>
using namespace std;
class person {
public:int a;int b;int c;person() {cout << "person的无参构造函数" << endl;}person(int a1) {a = a1;cout << "person的有参构造函数" << endl;}person(const person &p) {a = p.a;cout << "person的拷贝构造函数" << endl;}~person() {cout << "person的析构函数" << endl;}
};
void fun(person A) {cout << A.a << ' ' << A.b <<' '<<A.c << endl;
}
int main() {person A(10);A.b = 90;cout << A.a << ' ' << A.b << ' ' << A.c << endl;fun(A);return 0;
}

1.3.3以值方式返回局部对象

同做做参数一样,也只复制拷贝函数中定义要复制的部分,并不是完全复制。

#include <iostream>
using namespace std;
class person {
public:int a;int b;int c;person() {cout << "person的无参构造函数" << endl;}person(int a1) {a = a1;cout << "person的有参构造函数" << endl;}person(const person &p) {a = p.a;cout << "person的拷贝构造函数" << endl;}~person() {cout << "person的析构函数" << endl;}
};
person fun() {person A(10);A.b = 90;//已经赋值,但是形参还是随机值cout << A.a << ' ' << A.b << ' ' << A.c << endl;return A;}
int main() {person A=fun();cout << A.a << ' ' << A.b << ' ' << A.c << endl;return 0;
}

 1.4构造函数调用规则

默认情况下,c++编译器至少给一个类添加3个函数

1.默认构造函数(无参,函数体为空)

2.默认析构函数(无参,函数体为空)

3.默认拷贝构造函数,对属性进行值拷贝(全部)

构造函数调用规则如下:

1.如果用户定义有参构造函数,c+不在提供默认无参构造,但是会提供默认拷贝构造

2.如果用户定义拷贝构造函数,C++不会再提供其他构造函数

代码:

#include <iostream>
using namespace std;
class person {
public:int a;int b;int c;person(int a1) {a = a1;cout << "person的有参构造函数" << endl;}~person() {cout << "person的析构函数" << endl;}
};
person fun() {person A(10);A.b = 90;//person B;   报错return A;}
int main() {fun();return 0;
}

1.5深拷贝和浅拷贝

浅拷贝就是简单的赋值操作,深拷贝就是

代码: 

#include <iostream>
using namespace std;
class person {
public:int a;int* b;person(int a1, int b2) {a = a1;b = new int(b2);}person(const person &p) {  //浅拷贝a = p.a;b = p.b;}~person() {  //浅拷贝if (b != NULL) {delete b;b = NULL;}}
};
void fun() {person a(10,90);person b(a);cout << b.a << ' ' << *b.b << endl;
}
int main() {fun();return 0;
}

 此时代码会报错,因为此时有两个析构函数,因此会是否两次相同地址的空间,此时要改为深拷贝。

代码: 

#include <iostream>
using namespace std;
class person {
public:int a;int* b;person(int a1, int b2) {a = a1;b = new int(b2);}person(const person &p) {  //深拷贝a = p.a;b = new int(*(p.b));}~person() {  if (b != NULL) {delete b;b = NULL;}}
};
void fun() {person a(10,90);person b(a);cout << b.a << ' ' << *b.b << endl;
}
int main() {fun();return 0;
}

 

  1.6初始化列表

C++提供了初始化列表语法,用来初始化属性。

 语法:构造函数()  :  属性值1(值1),属性值2(值2)....... { }

代码:

#include <iostream>
using namespace std;
class person {
public:int a;int b;int c;person(int a1,int b1,int c1) :a(a1), b(b1), c(c1) {  //初始化列表}
};
void fun() {person p(30, 3,78);cout << p.a << ' ' << p.b << ' ' << p.c << endl;
}
int main() {fun();return 0;
}


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

相关文章

TouchGFX之缓存位图

位图缓存是专用RAM缓冲区&#xff0c;应用可将位图保存&#xff08;或缓存&#xff09;在其中。 如果缓存了位图&#xff0c;在绘制位图时&#xff0c;TouchGFX将自动使用RAM缓存作为像素来源。位图缓存在许多情况下十分有用。 从RAM读取数据通常比从闪存读取要快&#xff08;特…

Mapbox加载arcgis的底图

成果图 这种底图基本上都是按照raster来加载的&#xff0c;主要就是知道地址了&#xff0c;拼参数 具体参数请参考官网 https://developers.arcgis.com/rest/services-reference/enterprise/export-map.htm 源码 我的服务列表是这样的 http://XXXX:XXXX/arcgis/rest/services/…

【k8s】kube-proxy 工作模式

文章目录 Userspace模式&#xff1a;iptables模式&#xff1a;负载均衡&#xff08;Load Balancing&#xff09; LB轮询&#xff08;Round Robin&#xff09;&#xff1a;SessionAffinity&#xff1a;最少连接&#xff08;Least Connection&#xff09;&#xff1a;IP哈希&…

uni-app监听页面滚动

在uni-app中可以通过监听页面滚动事件来实现滚动效果或响应滚动事件 在需要监听滚动的页面或组件中&#xff0c;添加一个scroll元素&#xff0c;用于容纳内容并实现滚动效果。 <template><view class"container"><scroll-view scroll-y scroll"…

深入了解==和equals的区别

1. 浅说和equals的区别 &#xff08;1&#xff09;比较的类型 不一样 可以比较基础数据类型和引用类型&#xff0c;比较基础数据类型的数据时比较的是值&#xff0c;比较引用对象时比较的是引用的地址。 equals比较引用类型&#xff0c;默认比较的是两个引用对象的引用地址&a…

python:优化一EXCEL统计用类封装一下

# encoding: utf-8 # 版权所有 2023 涂聚文有限公司 # 许可信息查看&#xff1a; # 描述&#xff1a; # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 311 # Datetime : 2023/9/17 5:40 # User : geovindu # Product : PyCharm # Proj…

redis info 详解(InsCode AI 创作助手)

redis info 详解 选项说明&#xff1a; Redis的INFO命令返回了关于Redis服务器的各种信息和统计数据&#xff0c;这些信息可以帮助您监控和管理Redis实例。INFO命令的输出是一个包含多行文本的字符串&#xff0c;包括了各种不同的信息类别。以下是一些常见的INFO命令输出中包…

[运维|数据库] PostgreSQL数据库对MySQL的 READS SQL DATA 修饰符处理

在 PostgreSQL 中&#xff0c;访问权限通常是通过数据库角色和表级别的权限进行管理&#xff0c;而不需要类似 MySQL 中的 READS SQL DATA 修饰符。 要在 PostgreSQL 中管理数据库对象的访问权限&#xff0c;您可以使用以下 SQL 命令&#xff1a; GRANT&#xff1a;授予用户或…