C++学习笔记
1.new关键字,开辟内存
new 数据类型(具体值) 开辟连续数组 new 数据类型[数组长度]
2.引用
引用的本质就是指针常量 int &a=b 等同于 int * const a=&b;
(1)引用做函数的返回值
int& test()
{
int a=1; return a;
}
此时返回的是局部变量a的引用,因此在函数运行后就释放了
int& test()
{
static int a=1; return a;
}
此时由于是静态变量,所以不会释放,并且函数可以用作可修改的左值
test()=1000; 表示调用函数后返回a的引用,此时就表示修改a的值
(2)常量引用
通常用来修饰形参,使得形参不可修改
例如:void test(const int &a) 此时a的值不可以被修改
3.函数的高级用法
(1)函数的形参可以设置默认值,且默认值后边的参数都要设置默认值。
(2 ) 函数的占位参数 void test(int) 必须传值,但也可以设置默认值, int = 数。
4.类
(1) 构造函数分类
有参构造和无参构造、拷贝构造
拷贝构造 类名(const 数据类型 &名);
(2)构造函数调用
1.()调用 有参:类名 p(参数),无参 : 类名 p 注意创建无参时不能加括号,加了后编译器会认为这个是函数的声明。
2.显示调用 例如 Person p=Person(参数) 调用拷贝构造 Person p=Person(对象)
- 注意:Person() 是一个匿名对象,在执行完这行后会自动释放。
3.隐式转换法 Person p=参数 调用拷贝构造 Person p=对象
(3)拷贝构造函数的调用时机
1.使用一个已经创建完毕的对象来初始化一个新对象
2.值传递的方式给函数参数传值
3.以值的方式返回局部对象
(4) 构造函数调用规则
默认情况下,编译器会自动提供三种构造函数
1.默认无参构造
2.默认有参构造
3.默认拷贝构造,对属性进行值拷贝
调用规则
1.如果用户定义了有参构造,则编译器不再提供默认的无参构造函数,但提供默认拷贝构造
2.如果用户定义了拷贝构造函数,则编译器不再提供其他任何构造函数
(5)深拷贝和浅拷贝
编译器默认的拷贝构造函数就是浅拷贝,它是一种值拷贝。
深拷贝指的是在堆区重新开辟一块空间用来存储。
(6) 初始化列表
和构造函数一样可以给成员属性进行初始化操作,格式 :构造函数(参数) : 属性(值),....
(7) 类中含有其他类的成员属性时,先执行其他类 再执行本类,析构函数相反.
(8) 静态成员
1.静态成员变量
(1)所有对象共享同一份数据
(2)编译时就分配内存,所以在全局区
(3)类内声明,类外初始化
2. 静态成员函数
(1)所有对象共享同一个函数
(2)静态成员函数只能访问静态成员变量。
(9) 成员变量和成员函数分开存储
空对象占用一个字节,当定义了成员变量时,占用成员变量空间大小。
静态成员变量和静态成员函数以及非静态成员函数都不属于对象上的。
(10)this指针用法
1.this指针指向的是被调用函数对应的对象的地址
2.this指针用来区分形参和成员变量同名
3.在类的非静态成员函数中返回对象本身 *this :this指向对应的对象的地址,*this就是对象本身。
(11)空指针调用成员函数
调用的成员函数中如果访问了成员变量,则需要进行特殊判断。
(12)const 修饰成员函数
1.常函数:在成员函数后面加const 称为常函数。常函数内不能修改成员属性,但成员属性声明时加mutable后可以修改。
2.常对象:定义对象时在前面加const 。常对象不能修改成员属性,且只能调用常函数。
(13)友元函数 :可以访问类中私有成员的函数
1.全局函数做友元: 在类中声明友元全局函数
格式 friend + 函数声明;
2.类做友元 格式: friend class 类名;此时可以访问类中私有属性。
3.成员函数做友元,让某一个类中的一个成员函数可以访问另一个类中的私有成员。
格式: friend void 类名::函数名();
(14)运算符重载,对现有的运算符进行重载,使得可以适应不同的数据类型
运算符重载函数可以支持函数重载
1.加法重载, 可以使用成员函数(operator+(传参))或全局函数(operator+(两个参数))实现。
假如 Person p3=p1.operator+(p2) == Person p3=p1+p2;
Person p3=operator+(p1,p2) == Person p3=p1+p2;
2.左移运算符重载 自定义输出
只能用全局函数实现
3.递增运算符重载
4.赋值运算符重载
5.关系运算符重载
6.函数调用运算符重载
(15) 继承
1. 继承方式
public 公共继承 protected保护继承 private 私有继承
2.私有属性也继承到子类中了,但被编译器给隐藏了,因此访问不到,但仍然占内存
3.继承中的构造和析构执行顺序
在创建子类对象时会先创建父类再创建子类,即先调用父类构造再调用子类构造,析构函数相反。
4.同名的成员处理
当出现同名成员属性时,子类对象可以直接访问子类中的同名成员。
子类对象访问父类中的同名成员时需要加作用域。
当子类对象拥有与父类对象中同名的成员函数时,子类会隐藏父类中所有的同名函数,需要访问父类中的同名函数时需要加作用域。
5.同名静态成员处理和以上一样只不过使用类名访问时格式为: B::A::成员属性/成员函数
6.多继承
语法格式 class 子类 :继承方式 父类,继承方式父类。。。
注意,当多个父类中出现同名成员时,需要指明作用域
7.菱形继承
如图中,羊驼类有两个父类的age,要使用作用域加以区分。
注意,由于只需要一份数据就够了,所以用虚继承来解决 :即在继承前加virtual
底层原理:两个父类的age是指针指向了动物类的age,因此他们共享一份数据。
8.动态多态
满足的条件 :
(1)要有继承关系 。 (2)子类要重写父类的虚函数
使用: 使用父类的指针或引用指向子类对象
动态多态原理:
多态的优点:
(1)代码组织结构清晰
(2)可读性强
(3)利于后期的扩展和维护
9.纯虚函数和抽象类
纯虚函数:virtual 返回值类型 函数名(参数列表) =0; 类中有纯虚函数时,为抽象类
抽象类:无法实例化对象 子类必须重写纯虚函数,否则也为抽象类
10.虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
1.·可以解决父类指针释放子类对象·
2.都需要有具体的函数实现
虚析构和纯虚析构区别: 如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:虚析构 virtual ~类名(){} 纯虚析构 virtual ~类名()=0;
注意:当使用多态时,如 A *a=new B; 如果delete a的话,则执行的是A的析构函数,并释放掉B的内存,但是不会执行B的析构函数。