关于动态内存分配new 和 malloc 的区别是什么?delete 和 free 的区别是什么?new 关键字和 malloc 函数的区别new 关键字是 C++ 的一部分malloc 是 C 库提供的函数new 以具体类型为单位进行内存分配malloc 以字节为单位进行内存分配new 在申请内存空间时可进行初始化malloc 仅根据需要申请定量的内存空间编程实验: new、delete 与 malloc、free#include <iostream>#include <cstdlib>using namespace std;class Test{private: int* mp;public: Test() { cout << “Test::Test()” << endl; mp = new int(100); } ~Test() { delete mp; cout << “~Test::Test()” << endl; }};int main(){ Test* pn = new Test; Test* pm = (Test*)malloc(sizeof(Test)); delete pn; free (pm); return 0;}输出:Test::Test()~Test::Test()分析:new Test; ==> 在堆上创建一个对象,构造函数被调用(Test*)malloc(sizeof(Test)); ==> 在堆上申请 sizeof(Test) 大小内存,构造函数未被调用,对象未正常创建delete pn; ==> 销毁对象, 归还内存,析构函数被调用free(pm); ==> 仅归还内存,析构函数未被调用当 delete 与 free 混用,会发生什么呢?delete –> free :int main(){ Test* pn = new Test; free (pn); // 注意这里! return 0;}输出:Test::Test()分析:free 可以释放 new 申请的堆空间,但析构函数未被调用,对象未正常销毁(实例中,导致系统资源未泄漏!!)free –> delete :int main(){ Test* pm = (Test*)malloc(sizeof(Test)); delete pm; // 注意这里! return 0;}输出:~Test::Test()分析:delete 可以释放 malloc 申请的堆空间,不合法对象的析构函数被调用!运行结果将是不确定的!(示例中,将delete一个野指针指向的内存空间)结论: C++ 中杜绝 malloc、 free 的使用new 和 malloc 的区别new 在所有 C++ 编译器中都被支持malloc 在某些系统开发中不能调用new 能够触发构造函数的调用malloc 仅分配需要的内存空间对象的创建只能使用 newmalloc 不适合面向对象开发delete 和 free 的区别delete 在所有 C++ 编译器中都被支持free 在某些系统开发中不能调用delete 能够触发析构函数的调用free 仅归还之前分配的内存空间对象的销毁只能使用 deletefree 不适合面向对象开发关于虚函数构造函数是否可以成为虚函数?析构函数是否可以成为虚函数?构造函数不可能成为虚函数在构造函数执行结束后,虚函数表指针才会被正确的初始化析构函数可以成为虚函数析构函数在对象销毁之前被调用,意味着虚函数表指针仍然正确的指向虚函数表建议在设计类时将析构函数声明为虚函数编程实验: 构造,析构,虚函数test_1.cpp#include <iostream>using namespace std;class Base{public: Base() { cout << “Base()” << endl; } virtual void func() { cout << “Base::func()” << endl; } ~Base() { cout << “~Base()” << endl; }};class Derived : public Base{public: Derived() { cout << “Derived()” << endl; } virtual void func() { cout << “Derived::func()” << endl; } ~Derived() { cout << “~Derived()” << endl; }};int main(){ Base* p = new Derived(); // 注意这里! // … delete p; return 0;}输出:Base()Derived()~Base()分析: 为什么 子类 的析构函数没有被调用呢?Base* p = new Derived(); ==> 因为赋值兼容性,编译通过。delete p; ==> 编译器考虑安全性,根据指针类型进行对象销毁析构函数声明为虚函数的意义 1:test_2.cpp#include <iostream>using namespace std;class Base{public: Base() { cout << “Base()” << endl; } virtual void func() { cout << “Base::func()” << endl; } virtual ~Base() // 注意这里! { cout << “~Base()” << endl; }};class Derived : public Base{public: Derived() { cout << “Derived()” << endl; } virtual void func() { cout << “Derived::func()” << endl; } ~Derived() { cout << “~Derived()” << endl; }};int main(){ Base* p = new Derived(); // … delete p; return 0;}输出:Base()Derived()~Derived()~Base()分析:当析构函数为虚函数时, delete p; 将根据 p 指向的实际对象决定如何调用析构函数。析构函数发生多态行为,保证系统资源尽可能得到释放!当声明构造函数为虚函数时,g++ 报错: virtual Base() { }error: constructors cannot be declared virtual 构造函数中是否可以发生多态?析构函数中是否可以发生多态?构造函数中不可能发生多态行为在构造函数执行时,虚函数表指针未正确初始化析构函数中不可能发生多态行为在析构函数执行时,虚函数表指针已经被销毁构造函数和析构函数中不能发生多态行为, 只调用当前类中定义的函数版本!关于继承中的强制类型转换继承中如何正确的使用强制类型转换?dynamic_cast 是与继承相关的类型转换关键字dynamic_cast 要求相关的类中必须有虚函数用于直接或间接继承关系的指针(引用)之间指针:转换成功: 得到目标类型指针转换失败: 得到一个空指针引用:转换成功: 得到目标类型引用转换失败: 得到一个异常操作信息编译器会检查 dynamic_cast 的使用是否正确类型转换的结果只可能在运行阶段才能得到编程实验: dynamic_cast 的使用#include <iostream>using namespace std;class Base{public: Base() { cout << “Base()” << endl; } virtual ~Base() { cout << “~Base()” << endl; }};class Derived : public Base{};int main(){ Base* p = new Base(); // 注意这里! Derived* pd = dynamic_cast<Derived*>(p); // 注意这里! if( pd != NULL ) { cout << “pd = " << pd << endl; } else { cout << “Cast error!” << endl; } delete p; return 0;}输出:Base()Cast error!~Base()析构函数声明为虚函数的意义 2 : 析构函数被声明为虚函数,保证 dynamic_cast 关键字可以被支持小结new / delete 会触发构造函数或者析构函数构造函数不能成为虚函数析构函数可以成为虚函数(推荐析构函数成为虚函数)构造函数和析构函数中都无法产生多态行为dynamic_cast 是与继承相关的专用转换关键字以上内容参考狄泰软件学院系列课程,请大家保护原创!