目录

1.构造函数和析构函数

2.构造函数的分类和调用

3.拷贝构造函数的调用时机

4.构造函数调用规则

5.深拷贝与浅拷贝

6.初始化列表

7.类对象作为类成员

8.静态成员

1.构造函数和析构函数

对象的初始化和清理分别利用构造函数和析构函数来进行。如果我们不提供构造和析构函数,编译器会自己提供构造函数和析构函数。

构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用,其主要特点如下:

  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 test01()
{Person p1;//此对象在栈上的数据,test01执行完毕后就会释放这个对象
}int main()
{test01();Person p2;//此对象在 main函数中执行到“systen(”pause“)“就停止了,不会被释放,所以不会进行析构函数的调用system("pause");return 0;
}

2.构造函数的分类和调用

分类:有参构造和无参构造、拷贝构造和普通构造。

调用:括号法、显示法、隐式转换法。

#include<iostream>
using namespace std;//构造函数的分类和调用//分类
//普通构造和拷贝构造函数
//有参构造和无参构造函数class Person
{
public://无参构造函数Person(){cout<<"Person的无参构造函数调用"<<endl;}//有参构造函数Person(int a){age = a;cout<<"Person的有参构造函数调用"<<endl;}//拷贝构造函数Person(const Person &p){//将传入的对象的所有属性,拷贝到自己身上age = p.age;cout<<"Person的拷贝构造函数调用"<<endl;}//析构函数~Person(){cout<<"Person析构函数调用"<<endl;}int age;
};void test01()
{//调用构造函数的方法//1、括号法Person p1;//默认构造函数调用,不要加小括号Person p2(10);//有参构造函数调用Person p3(p2);//拷贝构造函数调用//****调用默认构造函数的时候不要加小括号,"Person p1()"编译器会将这个默认为函数的声明//2、显示法Person p4;Person p5 = Person(10);//有参构造调用Person p6 = Person(p2);//拷贝构造函数调用Person(10);//不是放在 = 右边,单独使用的话叫匿名对象,相当于匿名有参构造,特点:当前行执行结束后,直接被注销掉cout<<"aaaaaa"<<endl;//****不要用拷贝构造函数初始化匿名对象,即Person(p3),编译器会默认为Person(p3)==Person p3,编译时会发生重定义错误。//隐式转换法Person p7 = 10;//相当于写了Person p7 = Person (10),有参构造函数Person p8 = p7;//拷贝构造函数
}int main()
{test01();system("pause");return 0;
}

3.拷贝构造函数的调用时机

C++拷贝构造函数调用时机:

  1. 使用一个已经创建完毕的对象来初始化一个新对象
  2. 值传递的方式给函数参数传值
  3. 以值方式返回局部对象
#include<iostream>
using namespace std;
//拷贝构造函数调用时机1
//1、使用一个已经创建完毕的对象来初始化一个新对象//2、值传递的方式给函数参数传值//3、值方式返回局部对象class Person
{public://默认构造函数Person(){cout<<"Person的默认构造函数的调用"<<endl;}//有参构造函数Person(int age){cout<<"Person的有参构造函数的调用"<<endl;m_Age = age;}//拷贝构造函数Person(const Person &p){cout<<"Person的拷贝构造函数的调用"<<endl;m_Age = p.m_Age;}//析构函数~Person(){cout<<"析构函数的调用"<<endl;}int m_Age;
};
//1、使用一个已经创建完毕的对象来初始化一个新对象
void test01()
{Person p1(20);Person p2(p1);cout<<"p2的年龄"<<p2.m_Age<<endl;
}//2、值传递的方式给函数参数传值
void doWork(Person p)
{}
void test02()
{Person p;doWork(p);
}//3、值方式返回局部对象
Person doWork2()
{Person p1;//p1时局部对象,doWork2()函数执行完后就会被释放。cout<<(int*)&p1<<endl;return p1;//局部变量,不是返回p1,重新创建一个新对象,拷贝p1的值。
}
void test03()
{Person p = doWork2();//p和p1不是同一个对象cout<<(int*)&p<<endl;//执行顺序:1、进行p1的创建,默认构造函数//2、打印p1的地址,//3、进行p的拷贝,拷贝构造函数;//4、p1释放,p1的析构函数//5、打印p的地址//6、p释放,p的析构函数。
}int main()
{/*test01();*//*test02();*/test03();system("pause");return 0;
}

4.构造函数调用规则

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

  1. 默认构造函数
  2. 默认析构函数
  3. 默认拷贝构造函数,对对象的属性进行值拷贝

调用规则如下:

  1. 如果用户定义有参构造函数,则编译器不再提供默认构造函数,但是会提供默认拷贝构造函数
  2. 如果用户定义拷贝构造函数,编译器不会提供其他构造函数
#include<iostream>
using namespace std;class Person
{public:Person(){cout<<"默认构造函数的调用"<<endl;}Person(int age ){cout<<"默认构造函数的调用"<<endl;m_Age = age;}Person(const Person &p){cout<<"拷贝构造函数的调用"<<endl;m_Age = p.m_Age;}~Person(){cout<<"析构函数的调用"<<endl;}int m_Age;
};void test01()
{Person p(18);p.m_Age = 18;Person p2(p);//如果注释掉默认构造函数和有参构造函数,只写了拷贝构造函数,编译器就不会提供默认构造函数和有参构造函数,此时编译就会发生错误cout <<"p2的年龄:"<<p2.m_Age<<endl;
}void test02()
{Person p;//如果注释掉默认构造函数,则编译器不会提供默认构造函数,此时编译会发生错误
}int main()
{test01();test02();system("pause");return 0;
}

5.深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝操作。

深拷贝:在堆区重新申请空间,进行拷贝操作。

如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题:重复释放操作。

#include<iostream>
using namespace std;class Person
{public:Person(){cout<<"默认构造函数的调用"<<endl;}Person(int age,int height){cout<<"有参构造函数的调用"<<endl;m_Age = age;m_Height = new int(height);//堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符delete//new返回的是该数据类型的指针}//自己实现拷贝构造函数解决浅拷贝带来的问题Person(const Person &p){cout<<"拷贝构造函数的调用"<<endl;m_Age = p.m_Age;/*m_Height = p.m_Height;*///编译器默认的m_Height = new int(*p.m_Height);//自己编写的拷贝实现语句,重新定义一个堆区用来接收拷贝数据}~Person(){//将堆区开辟的数据进行释放操作if(m_Height != NULL){delete m_Height;m_Height = NULL;}cout<<"析构函数的调用"<<endl;}int m_Age;  int *m_Height;
};void test01()
{Person p1(18,160);cout<<"p1的年龄:"<<p1.m_Age<<"身高为:"<<*p1.m_Height<<endl;Person p2(p1);//如果使用编译器提供的拷贝构造函数,会做浅拷贝操作,//浅拷贝直接将堆区的指针地址和内容拷贝过来,进行析构的时候会发生堆区内存的重复释放,编译会发生错误cout<<"p2的年龄:"<<p2.m_Age<<"身高为:"<<*p2.m_Height<<endl;
}int main()
{test01();system("pause");return 0;
}

6.初始化列表

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

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

#include<iostream>
using namespace std;class Person
{public://传统初始化操作/*Person(int a, int b, int c){m_A = a;m_B = b;m_C = c;}*///初始化列表初始化属性Person(int a, int b, int c): m_A(a), m_B(b), m_C(c){}int m_A;int m_B;int m_C;
}; void test01()
{Person p(10,20,30);//首先10先传给a,a再传给m_A,m_B和m_C的初始化同理cout<<"m_A = "<<p.m_A<<endl;cout<<"m_B = "<<p.m_B<<endl;cout<<"m_C = "<<p.m_C<<endl;
}int main()
{test01();system("pause");return 0;
}

7.类对象作为类成员

C++中,类的成员可以是另一个类的对象,成该类成员叫做对象成员。

#include<iostream>
using namespace std;
#include<string>class Phone
{public:Phone(string pName){m_pName = pName;cout<<"phone的构造函数调用"<<endl;}~Phone(){cout<<"phone的析构函数调用"<<endl;}string m_pName;
};
class Person
{public://Phone m_phone = pName,隐式转换法Person(string name ,string pName):m_Name(name), m_Phone(pName){cout<<"person的构造函数调用"<<endl;}~Person(){cout<<"Person的析构函数调用"<<endl;}string m_Name;Phone m_Phone;
};void test01()
{Person p("zhangsan","苹果手机");cout<<p.m_Name<<"拿着"<<p.m_Phone.m_pName<<endl;
}
//*****当其他类对象作为本类成员时,构造时先构造其他类对象,再构造自身
//*****析构的时候先析构自身,再析构其他类对象。int main()
{test01();system ("pause");return 0;
}

8.静态成员

静态成员变量:

  1. 所有对象共享
  2. 在编译阶段分配内存,程序没有运行之前就已经分配内存了,分配在全局区
  3. 类内声明,类外初始化
#include<iostream>
using namespace std;class Person
{public:static int m_A;//静态成员变量//所有对象共享//在编译阶段就分配内存//类内声明,类外初始化private:static int m_B;//*********静态成员变量也是有访问权限的,类外访问不到私有的静态成员变量
};
int Person::m_A = 100;void test01()
{Person p1;cout<<p1.m_A<<endl;Person p2;p2.m_A = 200;cout<<p1.m_A<<endl;
}void test02()
{//静态成员变量不属于某个对象,所有对象都可以用//因此静态成员变量有两种访问方式//1、通过对象进行访问Person p;cout<<p.m_A<<endl;//2、通过类名进行访问cout<<Person::m_A<<endl;
}int main()
{test01();test02();system("pause");return 0;
}

静态成员函数:

  1. 所有对象共享一个函数
  2. 静态成员函数只能访问静态成员变量
#include<iostream>
using namespace std;class Person
{public:static void func()//静态成员函数{m_A = 100;//静态成员函数可以访问静态成员变量/*m_B = 200*///不能调用非静态成员变量,因为其无法区分这是哪个对象的变量m_B。cout<<"static void func的调用"<<endl;cout<<m_A<<endl;}static int m_A;int m_B;private:static void func1()//私有静态成员函数也是有访问权限的,类外不能访问{cout<<"static void func1的调用"<<endl;}
};int Person::m_A = 0;void test01()
{//1、通过对象访问Person p;p.func();//2、通过类名访问Person::func();
}
int main()
{test01();system("pause");return 0;}

黑马C++学习总结之对象的初始化和清理相关推荐

  1. 【黑马程序员 C++教程从0到1入门编程】【笔记4】C++核心编程(类和对象——封装、权限、对象的初始化和清理、构造函数、析构函数、深拷贝、浅拷贝、初始化列表、友元friend、运算符重载)

    黑马程序员C++教程 文章目录 4 类和对象(类属性[成员属性],类函数[成员函数]) 4.1 封装 4.1.1 封装的意义(三种权限:public公共.protected保护.private私有)( ...

  2. C++ 对象的初始化和清理

    4.2对象的初始化和清理 ●生活中我们买的电子产品都基本会有出厂设置,在某-天我们不用时候也会删除一些自己信息数据保证安全 ●C++中的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理 ...

  3. c/c++教程 - 2.4.2.1~2 对象的初始化和清理,构造函数和析构函数,构造函数的分类和调用(有参构造,无参构造,普通构造,拷贝构造,括号法,显示法,隐式转换法,匿名对象)

    目录 4.2 对象的初始化和清理 4.2.1 构造函数和析构函数 4.2.2 构造函数的分类及调用 相关教程 4.2 对象的初始化和清理 生活中我们买的电子产品都基本会有出厂设置,在某一天我们不用时候 ...

  4. C++核心之类和对象——对象的初始化和清理下P110-P113

    4.2对象的初始化和清理 4.2.5深拷贝和浅拷贝 浅拷贝:简单的赋值拷贝操作. 深拷贝:在堆区重新申请空间,进行拷贝操作. 浅拷贝存在的问题:堆区内容重复释放. 代码1: #include<i ...

  5. C++阶段03笔记02【类和对象(封装、对象的初始化和清理、对象模型和this指针、友元、运算符重载、继承、多态)】

    C++| 匠心之作 从0到1入门学编程[视频+课件+笔记+源码] 目录 1.内存分区模型 2.引用 3.函数提高 4.类和对象 4.1.封装 4.1.1.封装的意义 --实例1:设计圆类 --实例2: ...

  6. IOS之学习笔记九(对象的初始化)

    1.oc对象的初始化 [[** alloc] init]  分2步,alloc是开辟内存,分配在堆区,这里java和C++都一样,init是进行初始化. [** new]和[[** alloc] in ...

  7. 《Java编程思想》学习笔记(三)——初始化与清理

    一.初始化 初始化其实就是为变量分配内存空间,并确定其初始值的过程.想了解Java中初始化的各种情况,首先要了解Java中变量的类型.根据自己的理解,将Java中的变量类型分成以下几种,虽然可能不太准 ...

  8. 学习笔记2——对象初始化和面向对象特性

    1.java类的初始化顺序: (1).在一个类中,初始化顺序由变量在类中的声明定义顺序决定,成员变量(非set方法和构造方法的初始化)的初始化发生在方法调用之前,包括构造方法. (2).静态变量在整个 ...

  9. 【C++】构造函数 利用构造函数对类对象进行初始化

    7个月之后的补充: 说真的,别再收藏这篇文章了,写的真的很拉跨,建议学习并收藏C++ 六个默认成员函数 + this指针_CPP的底层是哲学的博客-CSDN博客 也是我写的,质量会好很多!!!!!! ...

最新文章

  1. python3下载安装windows教程-Python3入门笔记(1) —— windows安装与运行
  2. maven的环境搭建
  3. 导师都有哪些“秘密”没有告诉你?
  4. 基于SpringBoot的CodeGenerator
  5. cifs mount 挂载共享目录_安装cifsutils解决linux挂载windows共享文件夹
  6. mysql 5.7安装完密码是多少_关于mysql5.7.18的安装并修改初始密码的图文教程
  7. 机器学习中的相似性度量(转载)
  8. Android Studio 安装说明
  9. Android 程序员计算器 开发记录-Git版本控制初步接触
  10. 配置思科交换机冗余链路汇聚
  11. 冰点--免积分下载百度文库、豆丁、道客巴巴文章
  12. java 文字串叠字检查_Java 正则表达式详细实例解析
  13. windows WTS 服务与桌面交互
  14. postgres mysql quora_DesktopReader for Quora
  15. 如何从课堂派上扒取直播视频
  16. 把单元格一分为二_怎么将一个单元格一分为二
  17. JTS Java空间几何计算、距离、最近点、subLine等 稳健的一比,持续更新中
  18. ubuntu分区大小
  19. 行人重识别常用数据集
  20. Navicat 使用IP连接本地mysql服务提示无权限访问

热门文章

  1. 利用poi 读取excel通用工具类
  2. matlab网页视频流,使用Matlab读取视频流文件
  3. matlab 对矩阵进行复制 || repmat
  4. RGB565 与RGB888的区别
  5. 最全的Python网站开发库!整理出来了!
  6. 使用线性回归构建房价预测模型
  7. 旁路电容和去耦电容基础知识
  8. 华为手机体验鸿蒙系统,再过40天,你就能在华为手机上,体验到鸿蒙系统了? - 区块网...
  9. hadoop是什么?特点?
  10. 用python获取指定路径下的所有目录路径和文件路径