看书时发现,C++中的基类的构造函数不能为虚函数(VC6.0中为虚函数是不能通过编译的),析构函数应该为虚函数(MFC中CObject的析构函数即为虚函数)。
通过以下面的代码,来看看这样的说法对不对:
测试一:
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base::Base()" <<endl;
}
~Base()
{
cout << "Base::~Base()" <<endl;
}
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived::Derived()" <<endl;
}
~Derived()
{
cout << "Derived::~Derived()" <<endl;
}
};
int main(int argc, char* argv[])
{
Derived d; // 依次调用Base::Base(),Derived::Derived()
// 程序结束时依次调用Derived::~Derived(),Base::~Base()
return 0; // 注意现在基类的析构函数不是虚函数,但是按照调用顺序不会造成内存泄露。
}
测试二:
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base::Base()" <<endl;
}
~Base()
{
cout << "Base::~Base()" <<endl;
}
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived::Derived()" <<endl;
}
~Derived()
{
cout << "Derived::~Derived()" <<endl;
}
};
int main(int argc, char* argv[])
{
Derived *d2 = new Derived(); // 依次调用Base::Base(),Derived::Derived()
Base *pBase = d2;
delete pBase; // 只调用了Base::~Base(),而没有调用Derived::~Derived()
// 因为这里基类的析构函数不是虚函数
return 0;
}
测试三:
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base::Base()" <<endl;
}
virtual ~Base()
{
cout << "Base::~Base()" <<endl;
}
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived::Derived()" <<endl;
}
~Derived()
{
cout << "Derived::~Derived()" <<endl;
}
};
int main(int argc, char* argv[])
{
Derived *d2 = new Derived(); // 依次调用Base::Base(),Derived::Derived()
Base *pBase = d2;
delete pBase; // 依次调用Derived::~Derived(),Base::~Base(),
// 因为这里基类的析构函数是虚函数
return 0;
}
总结:
(1) 假如你不打算使用多态(用基类指针指向派生类实例),基类析构函数是否为虚函数是无关紧要的。
(2) 假如你打算使用多态,一定要注意了,让基类的析构函数为虚函数。
PS: 对于非虚函数的调用,完全取决于指针的类型。因为非虚函数的地址在编译阶段就会根据指针的类型确定下来。举一个简单的例子,派生类有一个非虚函数f(),基类中不存在这样的函数。使用一个基类指针指向一个派生类实例后,假如你打算使用这个基类指针调用f(),编译器会让你打消这个念头(编译无法通过)。
分享到:
相关推荐
构造函数不能声明为虚函数主要是因为构造过程中对象的动态类型尚未确定,而析构函数可以声明为虚函数以确保正确释放资源并避免内存泄漏等问题。理解这些基本原则对于编写高质量、健壮的C++程序至关重要。
1. **动态类型与静态类型不匹配**:在析构函数中调用虚函数时,C++使用的是静态绑定,即根据对象的静态类型(即编译时已知的类型)来决定调用哪个函数版本,而不是动态类型(即运行时的实际类型)。因此,即使你期望...
在C++编程中,虚析构函数是一个至关重要的概念,特别是在处理对象的继承和多态性时。本文将深入探讨虚析构函数的作用、工作原理以及何时需要使用它。 首先,我们来理解什么是析构函数。析构函数是C++中的一个特殊...
然而,析构函数可以是虚函数,而构造函数不能是虚函数,这是为什么呢?今天我们就来详细解释这个问题。 首先,让我们来看一下为什么析构函数需要是虚函数。如果析构函数不是虚的,那么将只调用对应于指针类型的析构...
总之,理解并熟练运用构造函数、复制构造函数、析构函数、继承、虚函数和多态性是掌握C++面向对象编程的关键。它们共同构成了C++强大而灵活的类层次结构和对象模型,为复杂软件设计提供了坚实的基础。通过深入研究和...
C++中,有两种类型的析构函数:非虚析构函数和虚析构函数。对于基类,如果基类的析构函数声明为虚的(`virtual`),那么通过基类指针或引用删除派生类对象时,将调用正确的派生类析构函数,这是多态性的体现。不声明...
这时候如果析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。因此,构造函数不需要是虚函数,也不允许是虚函数。 从实现上看,vtable 在构造函数调用后才建立,因而构造函数不可能成为虚函数...
### 为什么构造函数不能是虚函数 #### 一、引言 在面向对象编程中,构造函数和虚函数是两个非常重要的概念。构造函数用于初始化对象的状态,而虚函数则支持多态性,允许基类指针或引用调用派生类的方法。这两种机制...
5. **不能重载**:同一个类中只能有一个析构函数,因此不能重载析构函数。 6. **可以是虚函数**:如果希望在派生类中覆盖基类的析构函数,则可以在基类中声明析构函数为虚函数。 #### 三、示例代码解析 下面通过给...
在C++中,析构函数的调用顺序与构造函数相反:先调用派生类的析构函数,然后逐级向上调用父类的析构函数,直至最基类的析构函数。 当我们涉及到类的继承时,构造函数和析构函数的调用顺序会变得更加复杂。例如,在...
在C++编程中,有一条重要的原则是避免在构造函数或析构函数中调用虚函数。这条箴言尤其对那些从C#或Java转向C++的开发者来说可能显得有些反直觉,因为在这些语言中,这样的调用通常是允许的。然而,在C++中,这样做...
- 不声明析构函数为虚函数。 - 指向基类对象的指针释放派生类对象。 - 结果:派生类的析构函数不会被调用,可能导致资源泄漏。 3. **虚析构函数的影响** - 将析构函数声明为虚函数。 - 指向基类对象的指针释放...
当我们谈论“C++规定与类同名的函数就是拷贝构造函数”时,实际上是指一个类中定义的与类名相同且参数为该类类型的函数,这就是拷贝构造函数。 拷贝构造函数是一种特殊的构造函数,用于初始化一个新对象为已有对象...
在构造函数中,这个指针可能指向基类的虚函数表,而在析构函数中也可能如此,除非派生类的析构函数被调用,这时虚函数表才被更新为派生类的虚函数表。 4. **示例输出解析**:从示例程序的输出可以看出,即使在构造...
上述代码中,`Base`的析构函数声明为虚函数,当`pBase`被删除时,会先调用`Derive`的析构函数,然后调用`Base`的析构函数。这体现了析构函数的多态性特性。 总之,理解C++中构造函数和析构函数的调用顺序以及何时...
与构造函数不同,析构函数不能被重载或继承。这意味着每个类都有且仅有一个析构函数,且派生类不会从基类继承析构函数。这是为了确保在对象生命周期结束时,每个类都能够正确地处理自己特有的资源。 在派生类中,当...
构造函数不能是虚函数,因为构造函数在对象创建时被调用,而此时虚函数表还未初始化。 7. **C++11的final关键字**: 从C++11开始,可以使用`final`关键字阻止子类进一步覆盖虚函数: ```cpp class Base { ...