今天Leen同学问我一个看似很简单的问题,父类的构造函数中调用了虚函数的话.那么在实例化子类对象时首先应该调用父类的构造方法,这时父类的构造函数中调用的虚函数应该是哪个?
其实这个问题,在语言设计的时候就是个两难的问题。
一、如果调用的是父类的函数的话,这个有点违反虚函数的定义。
二、如果调用的是子类的函数的话,这可能产生问题的:因为在构造子类对象的时候,首先调用父类的构造函数,而这时候如果去调用子类的函数,由于子类还没有构造完成,子类的成员尚未初始化,这么做显然是不安全的。
c++选择了第一种,而Java选择了第二种。
c++类的设计相对比较简陋,通过虚函数表来实现,缺少类的元信息。
而Java类的则显得比较完整,有super指针来导航到父类
super super
child------->father------>object
|--------------|------------|
class class class 类的元信息
这样Java与c++相比显得更动态了,因为可以通过反射来做很多c++不能做的工作了。事实上反射机制为面向对象的设计提供了强大的威力。
这或许和他们类的不同设计方法有关:c++通过查虚函数表,java通过super指针在完整的类结构中查找来实现多态。
class A{
public A(){
print();
}
public void print(){
System.out.println("A");
}
}
class B extends A{
public B(){
}
public void print(){
System.out.println("B");
}
}
class MainC{
public static void main(String []args){
A a = new B();
a.print();
}
}
输出B B
#include<iostream>
using namespace std;
class A{
public:
A(){
print();
}
virtual void print(){
cout << "A" << endl;
}
};
class B: public A{
public:
B(){
}
virtual void print(){
cout << "B" << endl;
}
};
int main(){
B b;
A &a = b;
a.print();
return 0;
}
输出A B
分享到:
相关推荐
然而,当我们尝试在构造函数中调用虚函数时,情况变得稍微复杂一些。下面我们将详细讨论这个问题。 首先,理解C++对象的构造过程至关重要。在创建一个对象时,构造函数会按照继承层次自底向上顺序执行。这意味着先...
- 这是因为构造函数调用的顺序是从基类到派生类,而在构造函数中调用虚函数时,虚拟表(VTable)中的指针还未被更新为最终派生类的版本,导致调用的总是当前类的函数。 4. **潜在的安全问题** - 如果允许在构造函数...
从实现上看,vtable 在构造函数调用后才建立,因而构造函数不可能成为虚函数。从实际含义上看,在调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数);而且构造函数的作用是提供初始化,在对象...
问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。 2. 从使用角度,虚函数主要用于在信息不全的情况下,能使...
3. 如果需要在子类构造函数中调用重写后的虚函数,可以考虑使用构造函数初始化列表或者在子类构造体内部完成,以确保对象完全初始化后再调用虚函数。 了解这个原理对于编写复杂继承结构的程序非常重要,因为它可以...
### C++箴言:避免析构函数调用虚函数 #### 概述 在C++编程中,理解和遵循良好的设计模式对于确保程序的稳定性和可维护性至关重要。其中一个经常被提及的原则是“避免在析构函数中调用虚函数”。这一原则在C++语言...
构造函数不能声明为虚函数主要是因为构造过程中对象的动态类型尚未确定,而析构函数可以声明为虚函数以确保正确释放资源并避免内存泄漏等问题。理解这些基本原则对于编写高质量、健壮的C++程序至关重要。
本资源提供的"winform 构造方法中调用虚方法源码"是一个关于面向对象编程的实例,探讨了如何在WinForm控件的构造函数中调用虚方法。 在C#或.NET编程中,构造函数是类的一个特殊方法,用于初始化新创建的对象。而虚...
C# 构造函数如何调用虚方法是一个重要的知识点,了解这个问题可以帮助开发者更好的理解和使用 C# 语言中的虚方法和构造函数。 首先,需要了解什么是虚方法。在 C# 中,用 virtual 关键字修饰的方法(属性、事件)...
继承作为面向对象编程的一种基本特征,其使用频率... 假设derived 虚继承自base类,那么derivd与base是一种“has a”的关系,即derived类有一个指向base类的vptr。(貌似有些牵强!某些编译器确实如此) 因此虚
这里,通过基类指针调用虚函数,根据指向的对象类型动态决定调用哪个版本的函数,体现了多态性的特点。 ### 总结 C++中类中函数的调用是面向对象编程的重要组成部分,它不仅提供了封装和抽象的能力,还支持继承和...
在C++编程中,有一条重要的原则是避免在构造函数或析构函数中调用虚函数。这条箴言尤其对那些从C#或Java转向C++的开发者来说可能显得有些反直觉,因为在这些语言中,这样的调用通常是允许的。然而,在C++中,这样做...
这是因为,构造函数是在对象创建时被调用的,而虚函数是在对象已经创建后被调用的。 派生类构造函数和析构函数的执行顺序是非常重要的。正确地理解和使用这两个函数,可以实现代码的重复利用和提高程序的效率。
2. 构造函数可以链式调用,即子类构造函数中可以调用基类的构造函数。 3. 构造函数不能是虚方法或抽象方法,也不能声明为static。 三、构造函数的应用场景 1. 初始化成员变量:通过构造函数,可以在对象创建时就...
通过指针或引用来调用虚函数,即使指针或引用指向的是基类类型,也能调用到子类的覆盖版本。 最后,关于对象的内存布局,C++的对象通常包含成员变量的存储空间,以及可能存在的虚函数表指针(如果类含有虚函数)。...
2. 显式构造函数调用:可以使用成员初始化列表(member initialization list)来指定子对象的构造函数,并传递参数。这种方式可以提高效率,因为避免了默认构造后再赋值的额外开销。 三、派生类构造函数 1. 继承...
这里,`m_width`, `m_length`, 和 `m_height` 在构造函数调用时直接初始化。 6. 显式构造函数: 显式构造函数通过使用`explicit`关键字来防止隐式类型转换,防止可能导致意外行为的自动类型转换。例如,如果`Box`...
在C#编程语言中,构造函数和析构函数是两个非常关键的概念,它们在对象生命周期管理中起到至关重要的作用。让我们深入探讨一下这两个概念及其在实际编程中的应用。 首先,构造函数是C#中用于初始化新创建对象的方法...