测试C++继承

class A{
public:
    virtual int test(int a=20){
        std::cout << "test A value=: "<< a<< std::endl; 
        return 0;
    }
};
class B: public A{
public:
    virtual int test(int a=100){
        std::cout << "test B value=: "<< a<< std::endl; 
        return 0;
    }
};
int main(){
    A*ptr=new B();
    ptr->test();
}

输出结果:test B value=: 20

解析(文心一言)

在C++中,当您定义一个继承体系,并且基类(A)和派生类(B)都有相同名称的虚函数(test)时,派生类中的函数会覆盖(Override)基类中的函数。但是,关于默认参数值的行为需要特别注意。

在您的例子中,基类A中的test函数有一个默认参数int a=20,而派生类B中的test函数也有一个默认参数int a=100。然而,重要的是要理解,当通过基类指针(或引用)调用一个虚函数时,使用的是基类中声明的函数签名,包括其默认参数值(如果有的话)。这意味着,即使实际上调用的是派生类中的函数体,其默认参数值也会是基类中声明的那个。

因此,在您的main函数中:

A* ptr = new B();
ptr->test();

这里调用的是B类中的test函数体,但是使用的是A类中声明的默认参数值20,而不是B类中声明的100

输出将会是:

test A value=: 20

这是因为ptr是指向A类型的指针,尽管它实际上指向一个B类型的对象。在C++中,当通过基类指针或引用调用虚函数时,函数解析(决定调用哪个函数体)是在运行时进行的(基于对象的实际类型),但是参数的解析(包括默认参数的解析)是在编译时进行的,基于指针或引用的静态类型。

如果您想根据对象的实际类型(即B)来动态地选择默认参数值,您需要在函数调用时显式地传递参数,或者在基类和派生类中通过其他机制(如重载函数或使用构造函数初始化)来设置这些值。但请注意,C++不直接支持根据对象的实际类型来选择默认参数值。

二、

class A{
public:
    virtual int test(int a=20){
        std::cout << "test A value=: "<< a<< std::endl; 
        return 0;
    }
};
class B: public A{
public:
    virtual int test(int a=100){
        std::cout << "test B value=: "<< a<< std::endl; 
        return 0;
    }
};
int main(){
    A*ptr=new B();
    ptr->A::test();
}

在您的代码中,您尝试通过基类指针 ptr 显式地调用基类 A 的 test 成员函数,但是您使用的语法 ptr->A::test(); 是不正确的。在C++中,当您通过指针或引用调用成员函数时,不能直接使用作用域解析运算符(::)来指定要调用的成员函数版本,除非该成员函数是静态的。

对于虚函数,调用哪个版本的函数(基类版本还是派生类版本)是在运行时根据对象的实际类型来决定的,但是您不能直接在调用时通过作用域解析来指定。不过,由于您想要调用基类 A 的 test 函数,并且该函数是虚函数,您实际上不能直接从派生类对象(通过基类指针)直接调用基类版本的函数,除非您使用某种形式的类型转换来绕过虚函数机制。

但是,有一个更简单且通常更合适的方法是,在基类 A 中提供一个非虚函数(或者一个静态函数,但在这个场景下静态函数可能不适用),或者通过其他方式(如构造函数、初始化列表或设置函数)来设置您想要的行为。

然而,如果您的目的是展示如何绕过虚函数机制来调用基类函数,您可以使用 static_cast 来将基类指针转换为指向基类类型的指针,但这在大多数情况下并不是一个好的做法,因为它破坏了多态性。

下面是一个使用 static_cast 的例子,但请注意这不是推荐的做法:

#include <iostream>  
  
class A {  
public:  
    virtual int test(int a = 20) {  
        std::cout << "test A value=: " << a << std::endl;  
        return 0;  
    }  
};  
  
class B : public A {  
public:  
    virtual int test(int a = 100) override { // 注意添加了 override 关键字来明确表示这是一个覆盖  
        std::cout << "test B value=: " << a << std::endl;  
        return 0;  
    }  
};  
  
int main() {  
    A* ptr = new B();  
    // 使用 static_cast 绕过虚函数机制,直接调用基类 A 的 test 函数  
    static_cast<A*>(ptr)->test(); // 输出: test A value=: 20  
  
    delete ptr; // 不要忘记释放内存  
}

在这个例子中,static_cast<A*>(ptr)->test(); 显式地将 ptr 转换为指向 A 类型的指针,并调用 A 类的 test 函数。但是,请注意,这通常不是处理多态的正确方式。在大多数情况下,您应该让多态机制正常工作,即根据对象的实际类型来调用相应的函数。如果您需要调用特定版本的函数,您应该重新考虑您的设计,看看是否有更好的方法来达到您的目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值