一、简单介绍本节的一些知识点:
1、什么是类?下面是类的基本的知识点
类,类似于C的结构体,也是用来定义变量的,叫实例化对象:如下
/*这里定义一个类是不会分配内存给它的,只有在实例化类的对象的时候才会分配内存如果是一个空类,则在实例化对象的时候,系统也会给它分配一个字节大小的内存虽然它是空的,但还是会有最小的内存(避免尴尬),因为你都要实例化对象了又因为它的类是空的又不给人家内存,说不过去。总结:1:对象的抽象是 类;类的具体化(实例化)就是对象2:类有什么用? 是将数据和操作封装成对象,实现封装,继承等特性,提高代码的复用性,灵活性*/
class demo
{//有类的成员权限:三个(共有属性,保护属性,私有属性)
public: //共有//一般有基本属性int a;/*一般有基本的行为,如写函数实现各种行为,函数可以在里面写,太长的可以在类外写,
类内声明即可protected: //保护int b;private: //私有int c;};int main()
{//实例化一个类的对象为 d1,其中的class可以省略。class demo d1; return 0;
}
2、什么是类的继承
/* 类的继承有什么用?-> 丰富了设计的方法(为设计模型做基础)类的继承都有哪些?有:9种,继承方式有:共有继承,保护继承,私有继承,又因为类的成员有共有的,保护的,私有的所以3*3 = 9种。所以派生类访问基类成员,只要是看继承权限方式的级别 和 基类成员本身的权限级别 哪个高则决定最终的访问方式。这里有一个重要的例子:
就是当继承方式是私有继承的时候,派生类会把基类的所有成员都会以私有的方式继承过来,所以在派生类外是不允许访问的,只能通过间接的访问。*///创建一个人的基类,人一般都有哪些共性
class people
{
public://人的基本属性string head; //有头string hand; //有手string foot; //有脚//基本行为void eat() //都要吃{}void sleep() //都要睡{}};//创建一个派生类,共有继承
class ximing : public people
{public://小明继承了人的基本属性,但它还有自己的属性string headsome; //长的帅string small_eye; //小眼睛//特有的行为void learn_well() //学习好{}void speak_well() //会说话{}};int main()
{return 0;
}
3、类的大小
/* 1:类的大小 = 数据成员(栈空间 + 堆空间)+ 虚表(有虚表函数才有虚表)2:用sizeof(类名或对象)3:如果是空类--则系统会自动的给这个类分配1个字节*/
4、什么是类的构造函数?
/*1:类的构造函数格式:
class demo
{ public:demo() //无返回值,函数名要和类名一样(不能是私有,保护属性,会报错){}
}2:类的构造函数的作用:在实例化对象的时候会自动的调用,帮我们初始化类的 共有,保护,私有的成员3:如没有定义任何构造函数,编译器会使用默认的构造函数,默认的构造是一个空的函数4:如果我们自定义了构造函数,则编译器不会帮我们生成构造函数5:构造函数可以重载,但在实例化对象的时候调用哪一个,则看你怎么实例化对象了。
5、什么是构造函数的初始化列表?
/*1:什么是构造函数的初始化列表?如下例子*/class DEMO
{
public:DEMO() //鸡肋{}DEMO(int set_a,int set_c):a(set_a),c(set_c) //这个就是初始化列表{}void Show(){cout<<this->a<<"---"<<this->c<<endl;}
private:int a;int c;
};
int main()
{class DEMO d1(12,55);d1.Show();return 0;
}2:构造函数初始化列表有什么用? 可以使程序员快速方便的初始化数据成员3:无参构造函数不支持初始化列表4:初始化列表不支持this指针
6、什么是构造函数的隐式调用和显示调用
/*1:显示调用:自己调用,很少用隐式调用:默认调用2:基本格式myclass obj1; //隐式调用“无参”的默认函数eg:class demo d1;myclass obj2(5); //隐式调用带一个参数的构造函数eg:class demo d2(5);myclass obj3 = myclass(); //显示调用默认无参的构造函数myclass obj4 = myclass(10); //显示调用带一个参数的构造函数
*///eg
class demo
{
public:demo(){cout<<"我是d1无操作"<<endl;}demo(int a){this->a = a;}demo(int , int b){this->b = b;}demo(int a, int b, int){this->a = a;this->b = b;}int a;int b;};int main()
{class demo d1; //在编译的汇编阶段调用demo(),隐式调用“无参”的默认函数class demo d2(10); //在编译的汇编阶段调用demo(int a),隐式调用带一个参数的构造函数return 0;
}/*3:如果使继承,派生类如何通过初始化列表初始化继承过来的基类属性呢?可以通过派生类的构造初始化列表显示调用 基类的构造 。格式为如下的例子,在第二个类里*/
//这个例子是怎么在派生类中怎么调用基类的构造函数?
//在派生类中的初始化列表 显示调用 基类的构造函数即可class F
{
public:F(){}F(string set_smo):smoke(set_smo){}string smoke;};//派生类C,共有继承
class C:public F
{
public:C(){}//这里的初始化列表不能调换基类的构造函数和派生类的构造函数,要先基构,后派构,否则会警告C(string set_phone, string set_smo):F(set_smo),phone(set_phone){}string phone;
};
7、什么是拷贝构造函数?
/* 1:什么是拷贝构造函数?就是可以直接初始化整个类的属性成员2:拷贝构造函数有什么用?可以理解赋值的操作,即把一个类的对象赋值给另一个对象3:拷贝函数的基本格式,函数名=类名(类名 const & tmp) ,因为拷贝的东西都是不能变的,
所以加const,引用是为了节约内存,减少不必要的副本的浪费。
*///例子如下://这个是拷贝构造函数的一个例子,将d1的值拷贝到d2中(可以理解为给d2进行赋值的操作)
class demo
{public:string str;demo(){}demo(string set_str):str(set_str) //构造函数并初始化{}//拷贝对象一定要有一个形参,一般为类对象的引用,demo(demo const & tmp){this->str = tmp.str; //可以不写,系统会自动帮你生成一个拷贝函数}
};int main()
{class demo d1("hello world"); //调用demo(string set_str):str(set_str)构造函数class demo d2(d1); //将d1的构造函数的初始化赋值到d2中,即调用demo(demo const & tmp)cout<<d2.str<<endl;return 0;
}
二、详细介绍每个知识点
1、类与对象 ---- C++是面向对象开发,面向类开发(口语化)
1)基本概念 --- 类对象不是基本的数据类型,不能使用memset等清空函数清空类对象
什么是面向过程编程?编程指的是 编写程序以程序功能为核心,根据功能模块去 按照 过程 实现函数的封装,最后按照过程 依次调用函数。⭐ 简单来说就是一个功能从无到实现的这么一个过程。什么是面向对象编程? 面向 类的设计 编程 ,纯软件开发以程序功能为核心,来设计类,最后实例化类对象即可。⭐简单来说就是某个事物的共性设计成一个基本的类(派生类则是这个基类的扩展),⭐实例化对象就是在创建一个事物下面是我们已经用过的类类型:string类:不是基本数据类型,而是C++语法基于C,在上层封装出来的,和int short有点区别类就比如结构体类型,也是用来定义变量的,叫做实例化对象(实例化对象也是申请空间的过程);struct xxx yyy;//yyy是结构体变量,申请空间,定义了变量class xxx iii;//iii是类对象,申请空间,实例化对象(拟人手法)对象就比如结构体类型对应的变量也就是说:对象的抽象是 类类的具体化(实例化)就是对象下面是简单的例子:
class demo
{//有类的成员权限:三个(共有属性,保护属性,私有属性)
public: //共有//一般有基本属性int a;/*一般有基本的行为,如写函数实现各种行为,函数可以在里面写,太长的可以在类外写,
类内声明即可protected: //保护int b;private: //私有int c;};int main()
{//实例化一个类的对象为 d1,其中的class可以省略。class demo d1; return 0;
}
2) 类的基本 语法补充
通过上面的代码,我们了解了 类使用的基本语法,如下:1)类的类型声明,引入类的关键字 class, 类的组成部分: 属性:变量行为:接口默认都是私有属性private,不能在类外使用,需要修饰成 public属性如果接口代码太多,全部封装到类中有点差强人意!我们封装在类的外面。
具体语法就是 类中函数声明,类外指定封装 返回值类型 类标识符::函数名字(形参列表){}2)类的对象实例化: 申请空间栈空间 class img_inf bmp; 堆空间 class img_inf * bmp_p = new class img_inf; //后面再用3) 类的语法 和 结构体非常相识,譬如:先声明类型之后才能定义变量,只不过C++叫做实例化对象类对象 和 结构体变量 访问成员都是用 .类对象指针 和 结构体指针变量 访问成员都是用 ->类型的声明是不占空间的,实例化对象的时候才申请空间4)关于this指针的理解:this指针变量 是在 实例化类对象的时候自动生成的,保存当前类对象的 地址当程序员实例化多个类对象的时候,会自动生成多个this指针当类成员变量是唯一的,则可以不用this这些类的基本语法了解之后,我们下面再学习类的三种权限属性!
2、类的成员权限和类的继承
1)类的成员权限
public 公有 公有段的成员是提供给外部的接口使用的.(类内和类外都行)
protected 保护 保护段成员在该类内,和它的派生类中可使用(派生类于类的继承有关)
private 私有 私有段成员仅在类中可见。 我们需要了解清除,什么是类内和类外:什么是类内:类 类型 中类 类型外的类函数中
① 公有属性的例子
#include <iostream>
using namespace std;class demo
{
public:int a = 10;
};int main()
{class demo demo_1;cout<<demo_1.a<<endl;//在类的外部接口main中使用类的公有属性成员areturn 0;
}
② 保护属性的例子
#include <iostream>
using namespace std;class demo
{
projected:int a = 10;
};int main()
{class demo demo_1;cout<<demo_1.a<<endl; //类外不能访问,会报错return 0;
}
③ 私有属性的例子
类中没有设置成员的属性,那么其默认的权限属性是:私有属性。
私有属性的成员,不能在类外使用同时它的派生类也不能使用,
#include <iostream>
using namespace std;class demo
{
private:int a = 10;
};int main()
{class demo demo_1;cout<<demo_1.a<<endl; //类外不能访问,会报错return 0;
}
④ 类的三种属性综合使用:
#include <iostream>
#include <string>using namespace std;//设计一个人的类
class people
{public:string peo_name;//获取peopl的信息void Get_people(string peo_name, int age, int phone_passwd);//显示people的信息void Show_people();protected:int age;private:int phone_passwd;};void people::Get_people(string peo_name, int age, int phone_passwd)
{this->peo_name = peo_name;this->age = age;this->phone_passwd = phone_passwd;
}void people::Show_people()
{cout<<"姓名:"<<peo_name<<endl;cout<<"年龄:"<<age<<endl;cout<<"手机密码:"<<phone_passwd<<endl;
}int main()
{class people Bardb;Bardb.Get_people("Bardb", 18, 999999);Bardb.Show_people();return 0;
}
2)类的继承:基类(父类) 派生类(子类)
为什么C++中有 类的继承机制? 丰富类的设计方法 --- 为设计模型做基础。譬如:猫科动物类:基类基类的共有属性:胡须爪子基类的共有行为:具有较好的弹跳力肉食动物虎:派生类继承了 猫科动物类,本来就有基类的属性和行为
狮子:派生类继承了 猫科动物类,本来就有基类的属性和行为自己固有的属性: 自己固有的属性:王字印记 爆炸头有条纹 无条纹
注意:派生类使用自己的成员 和 继承方式没有关系,取决的本身成员的属性。
有了继承,那么也就是说 派生类是可以去访问使用基类中的成员,那么该以什么方式访问呢?(这里要注意:如:若私有继承基类的成员,则在派生类中的会把基类的所有的成员划在私有的区域里,不管之前基类是共有还是保护的还是私有的,因为这是私有继承是级别最高的。)
总结:派生类访问基类成员, 只要看 继承权限方式的级别 和 基类成员本身的权限级别 哪个级别高决定 最终的访问方式
3)公有继承
1、公有继承,派生类使用基类的公有成员,是public属性访问,所以可以在派生类的外面和里面访问。
派生类内使用基类公有成员书写格式: this->基类标识符::基类成员派生类外使用基类公有成员书写格式: 派生类对象.基类标识符::基类成员派生类对象指针->基类标识符::基类成员
2、公有继承,派生类使用基类的保护成员,是protected属性访问,只能在派生类类内访问。也可以通过派生类去调用基类的公有或者保护成员间接去修改基类的私有成员。
3、公有继承,派生类使用基类的私有成员,是private属性访问,只能通过派生类去调用基类的公有或者保护成员间接去修改基类的私有成员。
共有继承示例1:
#include <iostream>
#include <string>using namespace std;//猫科动物的基类
class cat_animal
{
protected:string feature_1; //胡须string feature_2; //爪子};//老虎派生类,共有继承
class Tiger:public cat_animal
{
public:void Set_base_init(){this->cat_animal::feature_1 = "胡须";this->cat_animal::feature_2 = "爪子";}void Show_init(){cout<<this->cat_animal::feature_1<<"---"<<this->cat_animal::feature_2<<endl;}};int main()
{//实例化一个老虎class Tiger T;//共有继承的情况下,派生类如何使用基类的保护成员,直接在类内调用使用即可T.Set_base_init();T.Show_init();return 0;
}
共有继承示例2:
#include <iostream>
#include <string>using namespace std;//猫科动物的基类
class cat_animal
{
public: //共有的刀,也可以是用保护的刀void Set(){feature_1 = "胡须";feature_2 = "爪子";}void Show(){cout<<feature_1<<"--"<<feature_2<<endl;}protected:string feature_1; //胡须string feature_2; //爪子};//老虎派生类,共有继承
class Tiger:public cat_animal
{
public:void Set_base_init(){//借刀杀人的方式去访问修改基类的保护成员this->cat_animal::Set();}void Show_init(){this->cat_animal::Show();}};int main()
{//实例化一个老虎class Tiger T;//共有继承的情况下,派生类如何使用基类的保护成员,在派生类调用基类的保护或者共有的刀间接去修改值T.Set_base_init();T.Show_init();return 0;
}
共有继承示例3:
4)保护继承
1、保护继承,派生类使用基类的公有成员,是protected属性访问,能在派生类类内访问,也可以通过派生类去调用基类的公有或者保护成员间接去修改基类的公有成员。
2、保护继承,派生类使用基类的保护成员,是protected属性访问,能在派生类类内访问。也可以通过派生类去调用基类的公有或者保护成员间接去修改基类的公有成员。
3、保护继承,派生类使用基类的私有成员,是private属性访问,只能通过派生类去调用基类的公有或者保护成员间接去修改基类的公有成员。
保护继承示例1:
#include <iostream>
#include <string>using namespace std;//父亲类基类
class father
{
public:string smoke;protected:int money;private:int passwd;};//孩子派生类 ,保护继承
class child:protected father
{
public:void Set_base_init(){this->father::smoke = "中华"; //直接访问共有成员this->father::money = 1900; //直接访问保护成员}void Show_init(){cout<<this->father::smoke<<endl;cout<<this->father::money<<endl;}
};int main()
{//实例化一个xmclass child xm;//保护继承的情况下,派生类如何使用基类的保护成员?直接在派生类访问即可,或间接访问(借刀杀人)xm.Set_base_init();xm.Show_init();return 0;
}
保护继承示例2:
#include <iostream>
#include <string>using namespace std;//父亲类基类
class father
{
public:string smoke;void Set(){smoke = "中华";money = 1900;}void Show(){cout<<smoke<<"--"<<money<<endl;}protected:int money;private:int passwd;};//孩子派生类 ,保护继承
class child:protected father
{
public:void Set_base_init(){this->father::Set();}void Show_init(){this->father::Show();}
};int main()
{//实例化一个xmclass child xm;//保护继承的情况下,派生类如何使用基类的保护成员?在派生类间接访问(借刀杀人)xm.Set_base_init();xm.Show_init();return 0;
}
保护继承示例3:
#include <iostream>
#include <string>using namespace std;//父亲类基类
class father
{
public:string smoke;void Set(){smoke = "中华";money = 1900;passwd = 123456;}void Show(){cout<<smoke<<"--"<<money<<"--"<<passwd<<endl;}protected:int money;private:int passwd;};//孩子派生类 ,保护继承
class child:protected father
{
public:void Set_base_init(){this->father::Set();}void Show_init(){this->father::Show();}
};int main()
{//实例化一个xmclass child xm;//私有继承的情况下,派生类如何使用基类的私有成员?这个只能通过基类刀来访问修改了(借刀杀人)xm.Set_base_init();xm.Show_init();return 0;
}
5)私有继承
1、私有继承:派生类访问基类的公有成员,是属于私有访问,能在派生类中访问或者借刀杀人。
2、私有继承:派生类访问基类的保护成员,是属于私有访问,能在派生类中访问或者借刀杀人。
3、私有继承:派生类访问基类的私有成员,是属于私有访问,只能借刀杀人。
私有继承示例:私有继承这里放一个例子,因为级别最高,都只能通过间接访问的方式来访问
#include <iostream>
#include <string>using namespace std;//父亲类基类
class father
{
public:string smoke;void Set(){smoke = "中华";money = 1900;}void Show(){cout<<smoke<<"--"<<money<<endl;}protected:int money;private:int passwd;};//孩子派生类 ,私有继承,即将父亲的基类所有成员放在child里的private区域里,在child
//中可直接访问,但在child类外是不能访问的。
class child:private father
{
public:void Set_base_init(){//间接访问this->father::Set();//直接访问
// this->father::smoke = "中华";
// this->father::money = 1900;}void Show_init(){//间接访问this->father::Show();//直接访问
// cout<<this->father::smoke<<endl;
// cout<<this->father::money<<endl;}
};int main()
{//实例化一个xmclass child xm;//私有继承的情况下,派生类如何使用基类的共有和保护成员?直接在派生类中访问或者间接访问即可。xm.Set_base_init();xm.Show_init();return 0;
}
6)类的继承 语法理解以及在嵌入式开发中的应用场景
1:语法理解:派生类访问基类成员, 只要看 继承权限方式的级别 和 基类成员本身的权限级别 哪个高决定 最终的访问方式访问基类的私有成员和继承方式无关,永远只能借刀杀人如果是因为继承关系让基类的成员属性提升为私有的,该成员可以在派生中访问继承写法:class 派生类名字 : 继承方式 基类名字嵌入式开发中什么时候需要考虑使用继承语法:当有多个功能模块都属于同一种类型的时候,譬如:基类:硬件类 设备类派生类:液晶显示器类 触摸屏类摄像头类LED类蜂鸣器类....基类:娱乐类派生类:视频播放类音乐播放类游戏类
3、类的大小
1、类本身是一种数据类型,在没有定义对象(实例化对象)前是不占用内存空间的,
定义对象的时候才会分配空间
2、计算一个类的对象占用多少空间用sizeof(类名或对象) sizeof(int) 1)类的内存空间大小是其数据成员(非静态-非数据段)和虚表大小有关,
跟函数成员无关(静态变量和函数都属于那种全局存储域,是不可能存放在类对象中的)类大小 = 数据成员(栈空间+堆空间) + 虚表(有虚函数才有虚表)2)如果一个类中没有数据成员(空类),也没有虚表,那么这个类的大小规定为1个字节 。
操作系统里面最小的内存单位是字节
4、类的构造函数
① 构造函数概念
构造函数的作用:在申请类对象空间的时候,会被自动调用,我们可以利用这个C++语法机制,让构造函数帮我们初始化类的 公 保 私 成员。但是我们要注意的是他是在类外被自动调用的,所以要设置 为 公有属性!!!!构造函数函数名就是和类名一样,“”““”“而且是没有返回值《类型》的函数,因为帮你初始化”“””“。
如下所示:
class demo_class
{
public:demo_class();//构造函数 也是类的成员,如果不指定属性,则默认为私有的
};如果构造函数被你弄成了私有属性的(保护属性的也同理),那么编译器会报错,
因为构造函数就是在实例化对象时,在类外通过实例化的对象去自动调用构造函数,
而构造函数是私有的,那么就出现了语法矛盾性。
② 构造函数特点
① 如果自己没有定义任何构造函数,则编译器会使用默认构造函数。默认的构造函数是一个空的函数。
② 如果我们自定义了任何构造函数,那么编译器就“”不会“”帮助我们生成构造函数(这个易错点!!!)
③ 构造函数不能通过类对象直接调用
④ 构造函数可以重载,但是在实例化对象的时候只能调用其中一个,那么调用哪一个? 来看下面代码!如果没有主动选择,则默认调用无参构造
示例代码:
#include <iostream>
#include <string>using namespace std;//类的构造函数名要和类名一样,构造函数的重载例子
class demo
{
public:demo(){cout<<"我是d1无操作"<<endl;}demo(int a){this->a = a;}demo(int , int b){this->b = b;}demo(int a, int b, int){this->a = a;this->b = b;}int a;int b;};int main()
{class demo d1; //在编译的汇编阶段调用demo()class demo d2(10); //在编译的汇编阶段调用demo(int a)cout<<d2.a<<endl;class demo d3(11,20); //在编译的汇编阶段调用demo(int , int b)cout<<d3.a<<","<<d3.b<<endl; //d3.a是随机值class demo d4(30,40,111); //在编译的汇编阶段调用demo(int a, int b, int)cout<<d4.a<<","<<d4.b<<endl;return 0;
}
③ 构造函数的初始化列表
设计理念:构造函数会在定义类对象是自动被调用,所以有自动初始化类成员数据的作用(初始化成员代码需要我们自己写)。C++提供了一种语法,可以让程序员快速的初始化类成员数据:初始化列表。具体如下所示:
代码示例:
#include <iostream>
#include <string>using namespace std;//类的构造函数名要和类名一样,构造函数的初始化列表
class demo
{
public:demo(){cout<<"我是d1无操作"<<endl;}demo(int a, int b):a(a),b(b) //构造函数的初始化列表{}void Show_date(){cout<<this->a<<"--"<<this->b<<endl;}
private:int a;int b;};int main()
{class demo d1; //在编译的汇编阶段调用demo()class demo d2(10,50);d2.Show_date();return 0;
}
④ 关于构造函数的隐式调用和显式调用
注意:构造函数是在构建对象的时候才有的,在构建对象之前是没有的,
也就是说构造函数的意义用于创建初始化对象,而不是通过对象调用的。不管是隐式还是显式,都指的是实例化类对象的时候才去调用的
或派生类的构造函数通过初始化列表显示调用基类构造函数,具体的写法:显式调用:自己调用 不常用隐式调用:默认调用 常用MyClass obj1; // 隐式调用”无参“的默认构造函数MyClass obj2(5); // 隐式调用带一个参数的构造函数MyClass obj3 = MyClass(); // 显式调用默认无参的构造函数MyClass obj4 = MyClass(10); // 显式调用带一个参数的构造函数
⑤ 构造函数 和 继承 联系的问题
有了继承,实例化派生类的时候,继承过来的基类属性需不需要被初始化?答:需要,那么要通过什么方式去初始化呢?通过调用基类的构造函数去初始化,所以引入问题:派生类如何调用基类的构造函数?默认会调用“无参”基类的构造函数,但是鸡肋。我们会选择用”带参“的基类构造,在派生类的构造函数中的初始化列表显示调用基类构造。如果是继承,派生类如何通过初始化列表初始化继承过来的基类属性?可通过派生类的构造初始化列表显式调用 基类的构造函数(自主调用),具体语法如下:派生类的构造函数名字() : 基类的构造函数名字(){}在继承的前提下,初始化派生类对象时,需要满足 继承过来的基类成员
能够被基类的构造函数初始化,我们可以通过派生类的初始化列表主动选择哪一个基类构造函数,
如果自己不选,则默认调用基类的无参构造。实例化派生类对象时,基类的构造函数一定会被调用,派生类自己的构造函数也会被调用。 顺序是:基构 再 派构
示例代码:
#include <iostream>
#include <string>using namespace std;//这个例子是怎么在派生类中怎么调用基类的构造函数?
//在派生类中的初始化列表 显示调用 基类的构造函数即可class F
{
public:F(){}F(string set_smo):smoke(set_smo){}string smoke;};//派生类C,共有继承
class C:public F
{
public:C(){}//这里的初始化列表不能调换基类的构造函数和派生类的构造函数,要先基构,后派构,否则会警告C(string set_phone, string set_smo):F(set_smo),phone(set_phone){}string phone;
};int main()
{//实例化一个派生类对象class C c1("白沙","小米"); //先调用基构,后调用派构//所以输出是先输出烟,后输出sho手机cout<<c1.phone<<","<<c1.F::smoke<<endl;return 0;
}
5、拷贝构造函数
(就是给你直接初始化整个类的属性成员 --- 也叫作复制构造函数 --- 也就是说该构造函数的形参是本类对象的引用)
① 概念
拷贝构造函数是作用:当在实例化类对象的时候,需要拷贝的时候自动被调用拷贝的意识可以理解为,一个类对象 赋值 给另外一个类对象
我们如果没有自己写类的拷贝构造函数,那么编译的时候编译器会自动生成一个默认的拷贝构造函数
(只带一个;类对象的引用形参),帮我们进行拷贝和构造函数一样,唯一不同的是拷贝构造函数有形参,该形参接收一个该类的对象的引用。
拷贝构造函数是构造函数的重载。具体如下所示:
class demo_class
{public:string string_data;int xxx;demo_class();//无参构造demo_class(string string_data); //一个参数的构造函数demo_class(demo_class const & tmp_dome)//一个参数的拷贝构造函数{this->xxx = tmp_dome.xxx;}
};注意:1:拷贝构造函数的形参为什么是类对象的引用而不是直接一个类对象?减少对象副本内存空间申请2:为什么要用const修饰类对象?因为拷贝构造函数 只是为了复制 形参对应的对象中的内容,不需要修改
② 作用
拷贝构造函数中的拷贝可以理解成赋值,把一个类对象赋值给另外一个对象。
(简单点来说就是把形参的对象赋值给你定义的对象),
也就是初始化类对象的作用。具体写法如下:
代码示例:
#include <iostream>
#include <string>using namespace std;//这个是拷贝构造函数的一个例子,将d1的值拷贝到d2中(可以理解为给d2进行赋值的操作)class demo
{public:string str;demo(){}demo(string set_str):str(set_str) //构造函数并初始化{}//拷贝对象一定要有一个形参,一般为类对象的引用,demo(demo const & tmp){this->str = tmp.str; //可以不写,系统会自动帮你生成一个拷贝函数}
};int main()
{class demo d1("hello world"); //调用demo(string set_str):str(set_str)构造函数class demo d2(d1); //将d1的构造函数的初始化赋值到d2中,即调用demo(demo const & tmp)cout<<d2.str<<endl;return 0;
}
③ 拷贝构造函数中的深拷贝和浅拷贝
后面学习之后更新......
这一节的虽然长,但是是c++的精髓