问题总结
- 
问题一:关于动态内存分配
- 
new和malloc的区别是什么?
- 
delete和free的区别是什么?
- 
new关键字与malloc函数的区别
- 
new关键字是C++的一部分
- 
malloc是由C库提供的函数
- 
new以具体类型为单位进行内存分配
- 
malloc以字节为单位进行内存分配
- 
new在申请内存空间时可以进行初始化
- 
malloc仅根据需要申请定量的内存空间
- 
new在所有C++编译器中都被支持
- 
malloc在某些系统开发中是不能被调用
- 
new能够触发构造函数的调用
- 
malloc仅分配需要的内存空间
- 
对象的创建只能使用new
- 
malloc不适合面向对象开发
- 
delete和free的区别
- 
delete在所有C++编译器中都被支持
- 
free在某些系统开发中是不能调用的
- 
delete能够触发析构函数的调用
- 
free仅归还之前分配的内存空间
- 
对象的销毁只能使用delete
- 
free不适合面向对象开发
- 
范例程序
#include <iostream> #include <string> using namespace std; class Base { public: Base() { cout << "Base()" << endl; } ~Base() { cout << "~Base()" << endl; } }; class Derived : public Base { public: Derived() { cout << "Derived()" << endl; } ~Derived() { cout << "~Derived()" << endl; } }; int main() { Derived* d = new Derived; Derived* m = (Derived*)malloc(sizeof(Derived)); delete d; free(m); }
- 
运行结果
- 
问题二:关于虚函数的问题
- 
构造函数是否可以成为虚函数
- 
析构函数是否可以成为虚函
- 
构造函数不可能成为虚函数,在构造函数执行结束后,虚函数表指针才会被正确的初始化
- 
析构函数可以成为虚函数,建议在设计类时将析构函数声明为虚函数
- 
范例程序(如果父类的析构函数没有声明虚函数会带来什么后果)
#include <iostream> #include <string> using namespace std; class Base { public: Base() { cout << "Base()" << endl; } ~Base() { cout << "~Base()" << endl; } }; class Derived : public Base { public: Derived() { cout << "Derived()" << endl; } ~Derived() { cout << "~Derived()" << endl; } }; int main() { Base* p = new Derived; delete p; }
- 
运行结果
观察运行结果,可以知道程序执行了父类的构造函数,子类的构造函数,在delete指针p时,程序只调用了父类的析构函数,没有调用子类的析构函数。如果在构造函数中我们动态申请了内存,在析构函数中进行是否可以内存的操作,恰恰程序却跳过了析构函数函数,这样就会出现内存泄漏的问题!!
解决方法:将析构函数声明为虚函数
- 
范例程序
#include <iostream> #include <string> using namespace std; class Base { public: Base() { cout << "Base()" << endl; } virtual ~Base() { cout << "~Base()" << endl; } }; class Derived : public Base { public: Derived() { cout << "Derived()" << endl; } ~Derived() { cout << "~Derived()" << endl; } }; int main() { Base* p = new Derived; delete p; }
- 
运行结果
- 
构造函数中不可能发生多态行为,在构造函数执行时,虚函数表指针未被正确初始化
- 
析构函数中不可能发生多态行为,在析构函数执行时,虚函数表指针已经被销毁
- 
构造函数和析构函数中不能发生多态行为,只调用当前类中定义的函数版本!!
- 
范例程序
#include <iostream> #include <string> using namespace std; class Base { public: Base() { print(); cout << "Base()" << endl; } virtual ~Base() { cout << "~Base()" << endl; } virtual void print() { cout << "I'm Base" << endl; } }; class Derived : public Base { public: Derived() { print(); cout << "Derived()" << endl; } ~Derived() { cout << "~Derived()" << endl; } void print() { cout << "I'm Derived" << endl; } }; int main() { Base* bp = new Derived; delete bp; }
- 
运行结果
观察运行结果发现,对象的类型子类,在构造函数中如果调用虚函数,执行的是自身定义的虚函数版本,这也证明了在构造函数和析构函数中不能发生多态行为!
- 
问题三:关于继承中的强制类型转换
- 
dynamic_cast是与继承相关的类型转换关键字
- 
dynamic_cast要求相关的类中必须有虚函数
- 
用于有直接或者间接继承关系的指针(引用)之间,指针转换成功:得到目标类型的指针,指针转换失败:得到一个空指针。引用转换成功:得到目标类型的引用,转换失败:得到一个异常操作信息。
- 
编译器会检查dynamic_cast的使用是否正确
- 
类型转换的结果只可能在运行阶段才能得到
- 
范例程序
#include <iostream> #include <string> using namespace std; class Base { public: Base() { cout << "Base::Base()" << endl; } virtual ~Base() { cout << "Base::~Base()" << endl; } }; class Derived : public Base { }; int main() { Base* p = new Derived; Derived* pd = dynamic_cast<Derived*>(p); if (pd != NULL) { cout << "pd = " << pd << endl; } else { cout << "Cast error!" << endl; } delete p; return 0; }
- 
运行结果
- 
小结
- 
new/delete会触发析构函数和构造函数的调用
- 
构造函数不能成为虚函数
- 
析构函数可以成为虚函数
- 
构造函数和析构函数中都无法产生多态行为
- 
dynamic_cast是与继承相关的专用转换关键字
    主要记录的是学习听课的笔记
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号