目录
插入:
1.strcpy和memcpy的区别:
(头文件都是<string.h>)
1、复制的内容不同。 strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。 strcpy不需要指定长度,它遇到被复制字符的串结束符"0"才结束,所以容易溢出。 memcpy则是根据其第3个参数决定复制的长度。
int* tmp = new int[capacity]; //申请空间
memset(tmp, 0, sizeof(int) * capacity); //tmp每个元素赋值0,即 清空空间
memcpy(tmp, arr, sizeof(int) * size); //arr的内容拷贝到tmp,指定大小(arr的size)13
strcpy(tmp,arr); //arr的内容拷贝到tmp
2.exit
进程的退出最好是用三个终止函数( exit、_exit、 _Exit )其中的一个(后两者属于系统调用),当然建议 exit 即可
正常退出:exit(0)、exit( )
异常退出:exit(除0外的其他值)
0/其他值 表示退出状态,即把退出状态传给exit函数,正常和异常 表现为后期操作系统内部处理过程不同,但最后都会退出。
完整写是system.exit( );
一、基本概念1
1.类的封装性
类 将具有共性的 数据和方法 封装在一起,加以权限区分,用户只能通过 公共方法 访问 私有数据。
类的权限分为:private(私有)、protected(保护)、public(公有)
在类的外部,有public修饰的成员才可以被访问。在没有涉及继承和派生时,private和protected是同等级的,外部不允许访问。用户在类的外部 可以通过public方法 间接访问 private和protected是数据。
2.定义一个类
class关键字(注意有分号)
class Data
{
//成员变量
private: //类中不写权限默认private(私有)
int a;
protected:
int b;
public:
int c;
//成员方法
void showData(void)
{cout<<a<<b<<c<<endl;}
};
int main()
{
//类实例化一个对象
Data ob;
//类外不能直接访问 类的私有和保护数据,公有数据可以。
cout<<ob.c<<endl;
//类中的成员函数和成员变量,需要对象调用。
ob.showData();
}
设计一个类的步骤:
- 确定有哪些成员变量,成员变量为私有
- 确定操作这些变量的成员函数,成员函数为公有(Init函数+get函数+其他)
3.成员函数 类中声明,类外实现
注意成员函数要加 ::,以表明所属,和全局函数区分
一般都是 成员函数 类中声明,类外实现 ,类定义在.h文件,成员函数实现在.cpp文件
*成员函数 一般比 全局函数 传的参数要少
成员函数需要用某个成员变量去调用,传参时无需再传这个成员变量,因此参数变少。
二、构造函数
1. 构造函数 和 析构函数
构造函数 完成 初始化操作,析构函数 完成 清理操作。这2个函数都会被编译器自动调用。
2. 构造函数 的 概述
类实例化对象的时候,系统自动调用构造函数,完成对象初始化。
如果用户不提供构造函数,编译器会自动添加一个默认的构造函数(空函数)。
如果用户定义了一个构造函数(不管是有参还是无参),编译器都不再提供构造函数。
(这也就意味着,如果定义了一个有参构造函数,但是定义了一个无参的类的话,编译器将因找不到无参构造函数而报错)
3. 构造函数 的 定义方法
构造函数名 和 类名 相同,没有返回值(连void都不可以),可以有参数,可以重载。权限为public(因为肯定要外部传初始值,私有就无法调用了)
class Data{
public:
int mA;
public:
//无参构造函数
Data()
{mA=0;}
//有参构造函数
Data(int a)
{mA=a;}
//析构函数
~Data()
{cout<<mA<<endl;}
};
int main(){
//隐式调用无参构造函数(编译器自动调用)(推荐)
Data ob1;
//显式调用无参构造函数
Data ob2=Data();//这里其实也是先创建匿名对象,再把匿名对象的值赋给对象ob2
//隐式调用有参构造函数(推荐)
Data ob3(10);
//显式调用有参构造函数
Data ob4=Data(10);
//匿名对象(无参)
//当前语句结束,立即释放
Data();
Data(20);
//构造函数隐式转换(当 类中只有一个数据成员 时才可以这样直接赋值)
Data ob5=100;
三、析构函数
1.析构函数的定义方法
- 函数名和类名称相同,在函数名前加~,没有返回值类型,没有函数形参(不能被重载)。
- 当对象生命周期结束的时候,系统自动调用析构函数。
- 一般情况下,系统默认的空的析构函数就足够,不需要再写析构函数;
- 但如果一个类有 指向堆区空间的 指针成员,这个类必须写析构函数。
(因为析构函数只释放了指针变量,没有释放指针变量所指的堆区空间。需要写析构函数去释放指针成员所指向的堆区空间)
(示例见上)
2.析构函数的调用顺序
栈,先定义的后释放
四、拷贝构造函数
本质:有参构造函数
拷贝构造的调用时机:旧对象给新对象初始化,就会调用拷贝构造函数。
如果用户不提供拷贝构造,编译器会自动提供一个默认的拷贝构造,完成赋值动作(浅拷贝)。
只有存在指针成员变量,需要深拷贝时,才会去自己写拷贝构造函数。
1.拷贝构造的定义形式
名字 同 类名称,参数 是 当前类的常引用(特征)
2.拷贝构造 和 无参构造、有参构造 的关系
如果用户定义了 拷贝构造 或者 有参构造,都会屏蔽 无参构造。
如果用户定义了 无参构造 或者 有参构造,不会屏蔽 拷贝构造。
3.拷贝构造的几种调用形式
3.1旧对象给新对象初始化
3.2普通对象作为 函数参数,调用函数时
3.3普通对象 作为 函数返回值 ,返回值时
vs会发生拷贝构造:
- 函数 return 的作用:返回值+结束当前函数
- 返回的值 放在了 栈区的临时区域(要在临时区的固定地方申请一个匿名对象,然后把值赋给这个匿名对象,就相当于旧对象给新对象初始化)
- 用ob2去接函数返回值(即 接匿名空间的值,不然匿名空间函数执行完就释放了。即使没有Ob2接也会发生拷贝构造)
Qtcreater、linux不会发生拷贝构造:
用ob2直接接管ob1空间,而不需要临时匿名对象(即ob1空间没被释放,直接给ob2了)
3.4给对象取别名,不会调用拷贝构造
4.拷贝构造的深拷贝
如果类中没有指针成员,不用实现 拷贝构造 和 析构函数 。
如果类中有 指针成员 且指向堆区空间,必须实现 析构函数 释放指针成员指向的堆区空间,并且必须实现 拷贝构造 完成深拷贝。