C/C++:虚函数

本文探讨了C/C++中虚函数的一些限制,包括构造函数、内联函数、静态函数和友元函数不能声明为虚函数。同时,详细解释了为什么构造函数不能是虚函数,而析构函数通常是虚函数的原因。内容还涉及构造函数与虚函数的执行顺序、虚函数与参数的关系,以及继承和隐式转换的相关知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不能是虚函数的几类函数:{\red{不能是虚函数的几类函数:}}

1−构造函数{\green{1-构造函数}}1
2−内联函数{\green{2-内联函数}}2
3−静态函数{\green{3-静态函数}}3
4−友元函数{\green{4-友元函数}}4
5−普通非类成员函数{\green{5-普通非类成员函数}}5


构造函数与虚函数顺序:{\red{构造函数与虚函数顺序:}}

class A{
    public:
    A(){a();}
    virtual void a(){
        cout<<"A"<<endl;
    }
};

class B : public A{
    public:
    virtual void a(){
        cout<<"B"<<endl;
    }
};
int main(){
    B b;
    return 0;
}

输出&quot;A&quot;{\orange{输出&quot;A&quot;}}"A"
main函数中实例化b,调用B构造函数,若构造函数有参数则初始化参数。
因为B继承了A,调用A构造函数,若构造函数有参数则初始化参数。
因为A()调用了a(),执行A中函数a(),此时虚机制不起作用,不会执行B中的函数b(),
因为B构造函数未完成,可能存在未初始化成员变量,按逻辑编译器也不会让虚机制生效。
A::a()完毕后退出函数栈,A构造函数完毕后退出函数栈,B构造函数完毕后退出函数栈。


虚函数与参数:{\red{虚函数与参数:}}

class A{
    public:
    virtual void print(int i = 10){
        cout<<"A "<<i<<endl;
    }
};

class B:public A{
    public:
    virtual void print(int i = 20){
        cout<<"B "<<i<<endl;
    }
};

int main(){
    A a;
    B b;
    a.print();
    b.print();
    A *x,*y;
    x = &a;
    y = &b;
    x->print();
    y->print();
    return 0;
}

输出:“A 10 B 20 A 10 B 10&quot;{\orange{输出:“A\ 10\ B\ 20\ A\ 10\ B\ 10&quot;}}A 10 B 20 A 10 B 10"

前两组不解释。
第三组,当基类指针指向基类实例,则虚机制不会生效。
第四组,当基类指针指向派生类实例,则虚机制生效,
此时,由于是预定义参数,则先初始化参数,再执行对应虚函数,具体原因我也不清楚。


继承与隐式转换:{\red{继承与隐式转换:}}

  • 位于继承链前的类指针可以指向继承链后的类实例,反之不可以。
  • 位于继承链后的类实例可以隐式转换为继承链前的类实例,反之不可以。

为什么构造函数不可以是虚函数,而析构函数最好是虚函数?{\red{为什么构造函数不可以是虚函数,而析构函数最好是虚函数?}}

  • 从内存角度:虚函数通过虚表实现,但类在调用构造函数前并没有实例化,也就没有虚表,所以矛盾。

  • 从使用角度:构造函数是对象创建时自主调用的,并不是通过父类指针调用,虚构造没有意义。

  • 从实现角度,虚函数实现继承链上从上至下的多态,而构造函数是继承链上从下至上调用,两者实现上矛盾。

  • 从意义角度:虚函数是为了解决析构函数内存泄漏,构造不会内存泄漏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值