初始化列表
1. 提高运算性能
分析上面的结果:
(1)第一行:Test1 t1;构造一个Test1对象;
(2)第二行:输出对应Test2构造函数中的代码,用默认的构造函数初始化对象test1 // 这就是所谓的初始化阶段
(3)第三行:输出对应Test2的赋值运算符,对test1执行赋值操作 // 这就是所谓的计算阶段
2. 必须使用
const常量成员,因为常量只能初始化不能赋值,所以必须放在初始化列表里面引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化
C++封装
封装目的:将数据与函数整合,只提供接口,屏蔽细节
类内的数据可设为私有
C++继承
子类对象创建时,会先调用父类的构造函数
1.如果父类构造函数带参数
2.如果父类同时有带参和不带参的,则子类默认调用无参的
**c++**之哪些成员函数不能被继承
构造函数:在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。如果没有显式的构造函数,编译器会给一个默认的构造函数,并且该默认的构造函数仅仅在没有显式地声明构造函数情况下创建。
析构函数:析构函数也不会被子类继承,只是在子类的析构函数中会调用父类的析构函数。
运算符重载赋值函数:赋值运算符重载函数也不会被子类继承,只是在子类的赋值运算符重载函数中会调用父类的赋值运算符重载函数。
菱形继承问题——最顶层的父类会被两次调用
1. 数据冗余
2. 二义性
解决办法——虚继承,即两个父类虚继承顶层父类
强制类型转换
static_cast主要有如下几种用法:
用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类指针或引用)时,由于没有动态类型检查,所以是不安全的。
用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。(**static_cast** 可用于将 int 转换为 **char**。 但是,得到的 char 可能没有足够的位来保存整个 int 值。 同样,这需要程序员来验证 static_cast 转换的结果是否安全。)
把void指针转换成目标类型的指针(不安全!!)
把任何类型的表达式转换成void类型。(这样的转换通常用于避免编译器发出未使用变量的警告。)// static_cast_Operator.cpp// compile with: /LDclass B {};
class D : public B {};
void f(B* pb, D* pd) { D* pd ...
const小结
1.constexpr与const
constexpr修饰的变量允许编译器在编译阶段对其进行验证,检验变量的值是否为常量(如果认定变量为常量表达式,可声明为constexpr)
C++多态
——————————————————————多态:一个接口,多种方法
虚表
如果存在虚函数,那么该类的大小会多一个指针的大小,该指针指向虚函数表。
编译器把虚函数指针放在最前面
虚表的每个单元存放虚函数的地址
C++的多态性
这就是c++中的多态性,当c++编译器在编译的时候,发现Father类的Say()函数是虚函数,这个时候c++就会采用晚绑定技术,也就是编译时并不确定具体调用的函数,而是在运行时,依据对象的类型来确认调用的是哪一个函数,这种能力就叫做c++的多态性,我们没有在Say()函数前加virtual关键字时,c++编译器就确定了哪个函数被调用,这叫做早期绑定。——————————————————————
1.在成员函数内可以调用纯虚函数,在构造函数/析构函数内部不能使用纯虚函数。
如果一个类从抽象类派生而来,它必须实现了基类中的所有纯虚函数,才能成为非抽象类。
2.基类的析构函数为虚函数时
3.虚函数理解:实现多态性,定义父类指针指向子类对象,调用指针时访问的是子类的重载函数。
4.字节对齐+static不影响类大小+虚指针大小为8
5.对于含有虚函数的类, ...
