第55课.经典问题解析四
1.关于动态内存分配
new和malloc的区别是什么?
delete和free的区别是什么?
new关键字与malloc函数的区别:
a.
new关键字是c++的一部分
malloc是由c库提供的函数
b.
new以具体类型为单位进行内存分配
malloc以字节为单位进行内存分配
c.
new在申请内存空间时可以进行初始化(临时对象)
malloc仅根据需要需要申请定量的内存空间
d.
new能够触发构造函数的调用
malloc仅分配需要的内存
e.
对象的创建只能选择new,不能选择malloc(不能触发构造函数)
delete和free的区别
a.
delete关键字是c++的一部分
free是由c库提供的函数
b.
delete能够触发析构函数的调用
free仅归还之前分配的内存空间
c.
对象的销毁只能使用delete,不能选择free
eg:
#include <iostream>
#include <cstdlib>
using namespace std;
class Test
{
public:
Test()
{
cout << "Test::Test()" << endl;
}
~Test()
{
cout << "~Test::Test()" << endl;
}
};
int main()
{
Test* pn = new Test; // 分配内存空间(new Test),同时初始化这段内存
// 空间Test对象(临时对象)
// new能触发构造函数
Test* pm = (Test*)malloc(sizeof(Test)); //仅仅分配一段空间
delete pn; // delete能够触发析构函数
free(pm);
return 0;
}
2.关于虚函数
构造函数是否可以成为虚函数?
析构函数是否可以成为虚函数?
答案:
a.构造函数不可能成为虚函数
在构造函数执行过程中,虚函数表未被正确初始化。此时定义虚函数,使用虚函数表,必然错误。
在构造函数执行结束后,虚函数表指针才会被正确初始化
b.析构函数可以成为虚函数
析构函数在对象销毁前被调用,此时虚函数指针是正确的指向虚函数表的
建议在设计类时将析构函数声明为虚函数
eg:
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base()" << endl;
func();
}
virtual void func()
{
cout << "Base::func()" << endl;
}
//virtual ~Base()
~Base ()
{
func();
cout << "~Base()" << endl;
}
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived()" << endl;
func();
}
virtual void func()
{
cout << "Derived::func()" << endl;
}
~Derived()
{
func();
cout << "~Derived()" << endl;
}
};
int main()
{
Base* p = new Derived();
// ...
delete p; // 当析构函数未被定义为 virtual 时 delete p根据指针到类型来调用析构函数
// 此时只会调用父类的析构函数。而不会调用子类的析构函数。错误
// 当使用虚函数时,构成多态。此时编译器会根据p所指的实际对象来决定析构的调用
return 0;
}
===
构造函数中是否可以发生多态?
析构函数中是否可以发生多态?
答案:
a.构造函数中不可能发生多态行为
在构造函数执行时,虚函数表指针为被正确初始化
b.析构函数中不可能发生多态行为
在析构函数执行时,虚函数表指针已经被销毁
(这里注意,析构函数能被定义为虚函数。是因为调用虚函数时,虚函数表指针,还是健全的。
但是当析构函数被执行时,虚函数表指针就被销毁了,此时就无法使用虚函数来实现多态了)