该部分内容包括:
该部分内容包括:
野指针不是NULL指针,是未初始化或者未清零的指针,它指向的内存地址不是程序员所期望的,可能指向了受限的内存。
成因:
1)指针变量没有被初始化
2)指针指向的内存被释放了,但是指针没有置NULL
3)指针超过了变量的作用范围,比如b[10],指针b+11
智能指针,将基本类型指针封装为类对象指针(这个类肯定是个模板,以适应不同基本类型的需求),并在析构函数里编写delete语句删除指针指向的内存空间。
智能指针就是一种栈上创建的对象,函数退出时会调用其析构函数,这个析构函数里面往往就是一堆计数之类的条件判断,如果达到某个条件,就把真正指针指向的空间给释放了。
使用普通指针,容易造成堆内存泄露(忘记释放),二次释放,野指针,程序发生异常时内存泄露等问题等,使用智能指针能更好的管理堆内存。
注意:不能将指针直接赋值给一个智能指针,一个是类,一个是指针。
智能指针在C++11版本之后提供,包含在头文件
在C++98中,有std::auto_ptr
,但它有很多问题。 不支持复制(拷贝构造函数)和赋值(operator =),但复制或赋值的时候不会提示出错。所以可能会造成程序崩溃。
auto_ptr<string> p1(new string ("auto") );//#1
auto_ptr<string> p2; //#2
p2 = p1; //#3
在语句#3中,p2接管string对象的所有权后,p1的所有权将被剥夺,可防止p1和p2的析构函数试图刪同—个对象;
如果再访问p1指向的内容则会导致程序崩溃,因为p1不再指向有效的数据。std::auto_ptr
被unique_ptr代替。
std::move
。该部分内容包括:
友元提供了不同类的成员函数之间、类的成员函数和一般函数之间进行数据共享的机制。
通过友元,一个不同函数或者另一个类中的成员函数可以访问类中的私有成员和保护成员。
友元的正确使用能提高程序的运行效率,但同时也破坏了类的封装性和数据的隐藏性,导致程序可维护性变差。
详情见参考5
friend 类型 函数名(形式参数);
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
friend class 类名;
使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
多态是“一个接口,多种实现”,通过派生类重写父类的虚函数,实现了接口的重用。
多态包括编译时多态和运行时多态,编译时多态体现在运算符重载上,运行时多态是通过继承和虚函数来体现的。
类的继承中使用虚函数来重写(override)基类中的函数。
在实际开发时,一般面向接口开发,操作父类指针即可。运行时父类指针指向子类对象并可访问子类同名函数,这时父类的虚函数就提供了接口。
该部分内容包括:
在继承体系下,将父类的某个函数给成虚函数(即加上virtual关键字),在派生类中对这个虚函数进行重写,利用父类的指针或引用调用虚函数。通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。对于虚函数调用来说,每一个对象内部都有一个虚表指针,在构造子类对象时,执行构造函数中进行虚表的创建和虚表指针的初始化,该虚表指针被初始化为本类的虚表。所以在程序中,不管你的对象类型如何转换,但该对象内部的虚表指针是固定的,所以呢,才能实现动态的对象函数调用,这就是C++多态性实现的原理。
普通函数是静态编译的,没有运行时多态。
静态绑定和动态绑定是C++多态性的一种特性。
1)对象的静态类型和动态类型
静态类型:对象在声明时采用的类型,在编译时确定
动态类型:当前对象所指的类型,在运行期决定,对象的动态类型可变,静态类型无法更改
2)静态绑定和动态绑定
静态绑定:绑定的是对象的静态类型,函数依赖于对象的静态类型,在编译期确定
动态绑定:绑定的是对象的动态类型,函数依赖于对象的动态类型,在运行期确定
只有虚函数才使用的是动态绑定,其他的全部是静态绑定。
只有通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数,才能发生动态绑定。若使用静态对象调用虚函数,是无法发生动态绑定,这时只能调用基类的成员函数。
详情可见参考3。
基类中为其派生类保留一个名字,以便派生类根据需要进行定义。
包含一个纯虚函数的类被称为抽象类,比如说“动物”这样一个类不便于定义具体成员函数,其子类“长颈鹿”、“大象”等才应该定义具体的成员函数,这时候“动物”类适合定义定义为抽象类,成员函数创建为纯虚函数以提供接口。
纯虚函数的形式如下:
virtual returnType function() = 0;
抽象类不可以实例化,但可以定义指针。
C++11中可以使用override关键字来说明派生类中的虚函数以方便查错。
void f1() const override; // 子类虚函数重写f1
为了拒绝在子类中重写父类的函数,可以使用final,方便查错。
void f1() const final; // 父类函数不允许子类重写f1
某些情况希望对虚函数的调用不要进行动态绑定,而是强迫执行虚函数的某个特定版本。
这时候可以使用作用域运算符::
。
DerivedClass child;
double x = child -> BaseClass::function();
1)override,派生类覆盖基类的虚函数,实现接口的重用,返回值类型必须相同
特征:不同范围(基类和派生类)、函数名字相同、参数相同、基类中必须有virtual关键字(必须是虚函数)
2)overwrite,派生类屏蔽了其同名的基类函数,返回值类型可以不同
特征:不同范围(基类和派生类)、函数名字相同、参数不同或者参数相同且无virtual关键字
在子类中overwrite直接覆盖掉同名成员函数,对于子类对象来说,父类的同名函数是不可见的,就无法实现父类指针或引用调用子类同名函数了。
原文:https://www.cnblogs.com/lvjincheng/p/11317105.html