第五十五课、经典问题解析四
一、new和malloc、delete和free之间的区别
1、new和malloc
(1)、new关键字是c++的一部分
malloc是c库提供的函数
(2)、new是以具体类型为单位分配内存
malloc是以字节为单位分配内存
(3)、new在申请内存空间时可进行初始化
malloc仅根据需要申请定量的内存空间
(4)、new在所有c++编译器中都被支持
malloc在某些系统开发中是不能调用的
(5)、new能触发构造函数的调用
malloc仅分配需要的内存空间
(6)、对象的创建只能用new
malloc不适合面向对象的开发
2、delete和free
(1)、delete在所有c++编译器中都被支持
free在某些系统开发中是不能调用的
(2)、delete能触发析构函数的调用
free仅归还之前分配的内存空间
(3)、对象的销毁只能用delete
free不适合面向对象的开发
#include<iostream> #include<cstdlib>//说明malloc和free是函数 using namespace std; class Test { private: int *mp; public: Test() { mp = new int(100); cout << "Test()" << endl; cout << *mp << endl; } ~Test() { delete mp;
cout << "~Test()" << endl; } }; int main() { Test* t1 = new Test();//会调用构造函数,不能用free来释放,否则可能造成内存泄漏 Test* t2 = (Test *)malloc(sizeof(Test));//只分配需要的内存空间,不会调用构造函数,不能用delete释放,否则会将mp指针错误释放掉
delete t1;//调用析构函数 free(t2);//不会调用析构函数
return 0; }
二、构造函数、析构函数、虚函数、多态
1、构造函数不可以成为虚函数
(1)、在构造函数执行结束后,虚函数表指针才会被正确初始化
2、析构函数可以成为虚函数
(1)、建议在设计类时将析构函数声明为虚函数
3、构造函数里面不可能发生多态行为
(1)、构造函数执行时,虚函数表指针未被正确初始化
4、析构函数里面不可能发生多态行为
(1)、在析构函数执行时,虚函数表指针已被销毁
#include<iostream> using namespace std; class Base { public: Base()// error, can not be declared virtual { cout << "Base()" << endl; func();//不会发生多态,调用当前类里面的func() } virtual void func() { cout << "Base::func()" << endl; } virtual ~Base()//can be declared virtual { cout << "~Base()" << endl; func();//只调用当前类定义的版本 } }; class Derived : public Base { public: Derived() { cout << "Derived()" << endl; func(); } virtual void func() { cout << "Derived::func()" << endl; } virtual ~Derived() { cout << "~Derived()" << endl; func(); } }; int main() { Base* p = new Derived();//赋值兼容性原则 cout << endl; delete p;//若析构函数不是虚函数,则这里就会只调用父类的构造函数,而不调用子类的,会造成内存泄漏
//根据析构顺序,会先调用父类析构函数,然后调用子类析构函数 return 0; } //打印结果 /* Base() Base::func() Derived() Derived::func() ~Derived() Derived::func() ~Base() Base::func() */
三、继承中的强制类型转换
1、dynamic_cast是与继承相关的类型转换关键字
2、dynamic_cast要求相关类中必须有虚函数
3、用于有直接或间接继承关系的指针(引用)之间
(1)、指针
A、转换成功:得到目标类型的指针
B、转换失败:得到一个空指针
(2)、引用
A、转换成功:得到目标类型的引用
B、转换失败:得到一个异常操作信息
#include<iostream> using namespace std; class Base { public: Base() { cout << "Base()" << endl; } virtual ~Base()//使用dynamic_cast需要类中有虚函数,故这里将析构函数声明为虚函数 { cout << "~Base()" << endl; } }; class Derived : public Base { }; int main() { Base* p = new Base(); Derived* d = dynamic_cast<Derived*>(p);//dynamic_cast 可以将子类转换转换成父类,反之不行(子类中可能有新成员),可以判断父子关系 // Derived* p = new Derived(); //Base* d = dynamic_cast<Base*> (p);//这样就会转换成功,输出succefully if(d != NULL) { cout << "succefully!" << endl; } else { cout << "error" << endl;//结果会输出这个,说明转换失败 } cout << endl; delete p; return 0; }
四、小结
(1)、new/delete会触发构造函数或者析构函数的调用
(2)、构造函数不能成为虚函数
(3)、析构函数可以成为虚函数
(4)、构造函数和析构函数里面都不能产生多态的行为
(5)、dynamic_cast 关键字是与继承相关