C++重载与重写的各种问题

本文详细探讨了C++中的函数重载与重写概念,包括const关键字的作用、默认参数的影响及访问修饰符的影响,并通过实例展示了如何区分重载与重写。

C++重载与重写的各种问题

知识复习

在探究C++虚函数造成的各种重写的问题之前,我们先复习一下C++中的函数重载

1.const在函数重载中的定义

对于下几种情况,哪几个算是函数重载呢?

//情况1
void fun(int a);
void fun(const int a);

//情况2
void fun(int* a);
void fun(const* a);

//情况3
void fun(int* a)
void fun(int const * a);

//情况4
void fun(int *a)
void fun(int *const a);

答案是:2,3是函数重载,1,4是重定义

情况1

我们可以假设这样的调用情况

fun(1)

那么对于第一种定义,我们可以看到

int a=1

是可以的,而第二种定义

const int a=1

同样也没问题,所以这里我们也就可以理解这里为什么是重定义了

情况2

我们可以假设这样的调用情况

const int b=1;fun(&b);

那么对于第一种定义,我们可以看到

int* a=&b

是不可以的,因为const int*是不可以向int *装换的,而第二种定义

const int* a=&b

毫无问题,所以我们可以通过这种方法将两种方法区分出来,那么传入int*调用的是那种呢?是第一种,因为,第一种显然更匹配一些。

情况3

哈哈,const int *int const *是等价的,所以如同情况2一样

情况4

这种情况就和情况1类似,这里就不多做解释了

总结

在C++中,函数重载还是重定义靠的是,是否有一种调用情况能将两种函数区分开来,如果能就是重载,否则就是重定义。

const在重载与重写中的作用

我们考虑这样的情况,以下两个函数哪个是重载,哪个是重写?

class A
{
    public:
        void test_const(int a)
        {
        }
        void test_const_function(int a)
        {
        }
};

class B:public A
{
    public:
        //情况1
        void test_const(int a)
        {
        }
        //情况2
        void test_const_function(int a) const
        {
        }

}

答案是情况1是重写,情况2是重载

情况1

这个很简单,相当于上边的情况1,因为我们无法区分调用在传入相同参数调用哪个函数,所以是重定义,但是用在虚函数上边就变成了重写。

情况2

但这是为什么呢?

其实是因为在类里边

void test_const_function(int a)
{
}
        |
        |
        |会被改写成
        |
        v
void test_const_function(A&a,int a)
{
}


void test_const_function(int a) const
{
}
        |
        |
        |会被改写成
        |
        v
void test_const_function(const A&a,int a)
{
}

那么就变成了上边情况2,所以变成了重载,重写失败。

默认参数在重载与重写中的作用

情况如下,那些会调用成功呢?

class A
{
    void test_default_parament(int a,int b=4)
    {
        cout<<"A:"<<a<<" B:"<<b<<endl;
    }
}
class B:public A
{
    void test_default_parament(int a=0,int b=0)
    {
        cout<<"A:"<<a<<" B:"<<b<<endl;
    }
}
int main()
{
    B* bpoint=new B
    A* apoint=bpointer;
    //情况1
    apoint-> test_default_parament(1,2);
    //情况2
    apoint-> test_default_parament(1);
    //情况3
    apoint-> test_default_parament();

}

答案是情况1和情况2,情况3会被认为缺少参数

分析

根本原因是默认参数时静态绑定的

apoint-> test_default_parament(1);
        |
        |
        |
        V
apoint-> test_default_parament(1,4)
//绑定父类的默认参数

apoint-> test_default_parament(1);
        |
        |
        |
        V
apoint-> test_default_parament(1,0)
//绑定子类函数的默认参数

说以略微思考一下,就可以知道为什么上边会调用失败了吧,更深一步,我们也可以知道函数具体输出的结果

总结

最好的方法是,不要在虚函数中使用默认参数,如果我们真的想用怎么办呢,世界之大,方法总会有的么。

private,public在重载与重写中的作用

有以下几种情况,哪几种会调用成功呢?

class A
{
    public:
        virtual void Test_public()
        {
            cout<<"father"<<endl;
        }
    private:
        virtual void Test_private()
        {
            cout<<"father"<<endl;
        }

};
class B:public A
{
    public:
        virtual const int Test_private()
        {
       }
    private:
        virtual void Test_public()
       {
       }
};
int main()
{
    B* bpointer=new B;
    A* apointer=bpointer;
    bpointer->Test_private();
    bpointer->Test_public();
    apointer->Test_public();
    apointer->Test_private();


    return 0;
}

嘿嘿,这里不给出答案了,比较难打,但是代码写的比较全,各位可以运行一下

为什么呢?其实本质这里也是一样的,对于操作权限都是静态绑定的

总结

  • 函数权限,默认参数都是静态绑定的
  • 函数重载和重定义都是依靠是否能有一种调用情况区分调用函数的
### C++ 中函数重载重写的区别和用法 #### 1. 定义概念 - **函数重载**是指在同一个作用域中定义多个同名的函数,但这些函数的参数列表必须不同(参数类型、数量或顺序)。这种机制使得程序员可以在同一作用域下使用相同的函数名称来实现不同的功能[^3]。 - **函数重写**是在派生类中重新定义基类中的虚函数的行为。它通常发生在继承关系中,目的是为了实现多态性,从而改变或扩展基类的功能[^1]。 --- #### 2. 参数返回类型的差异 - 对于**函数重载**而言,其核心在于参数的不同。即使返回类型不同,也不能作为区分重载的标准。只有当参数的数量、类型或者顺序发生变化时,才能构成有效的重载[^3]。 - 在**函数重写**的情况下,子类中的函数签名必须严格匹配父类中的虚函数签名(除了 `co-variant` 返回类型的情况),即函数名、参数列表以及常量修饰符都需一致[^1]。 --- #### 3. 使用场景 - **函数重载**适用于需要提供多种调用方式的情形。例如,在设计一个计算面积的函数时,可以针对圆形、矩形等形状分别编写具有不同参数的同名函数[^2]: ```cpp double area(double radius) { return 3.14 * radius * radius; } double area(double length, double width) { return length * width; } ``` - **函数重写**则主要用于支持动态绑定或多态性的场合。比如在一个图形绘制系统中,可以通过让各个具体形状类覆盖通用绘图接口的方法来实现特定行为[^1]: ```cpp class Shape { public: virtual void draw() = 0; // 纯虚函数 }; class Circle : public Shape { public: void draw() override { // 子类重写了draw方法 cout << "Drawing a circle." << endl; } }; ``` --- #### 4. 继承独立的关系 - **函数重载**并不依赖于继承结构;它可以存在于单个类内部甚至全局命名空间之中[^3]。 - 反之,**函数重写**总是伴随着继承而存在——只有当某个类是从另一个类派生出来的时候才可能出现这种情况,并且被重写的通常是带有 `virtual` 关键字声明的成员函数。 --- #### 5. 多态的支持程度 - **函数重载**本身不具备运行时期间决定实际执行哪个版本的能力,因此无法直接参基于对象实例的实际操作形式的选择过程。 - 相较之下,由于涉及到虚拟表(vtable)机制的应用,所以通过**函数重写**能够达成真正的运行期多态效果,这正是面向对象编程的一大特色所在。 --- ### 示例对比 以下是关于两者的一个简单例子: ```cpp #include <iostream> using namespace std; // 函数重载示例 void display(int value){ cout<<"Integer Value:"<<value<<endl; } void display(float value){ cout<<"Float Value:"<<value<<endl; } // 类层次结构下的函数重写示例 class Base{ public: virtual void show(){ cout<<"\nBase Class Function"<<endl; } }; class Derived: public Base{ public: void show(){ // Overriding base class function cout<<"\nDerived Class Function"<<endl; } }; int main(){ int i=10; float f=20.5f; // 调用重载函数 display(i); display(f); // 测试重写 Base* bptr=new Derived(); // Upcasting bptr->show(); // Calls overridden method delete bptr; return 0; } ``` 在这个程序里,我们既展示了如何利用不同类型的数据去触发相应的显示处理逻辑(`display`),也演示了一个典型的继承体系当中基础类别指向衍生实体变量所引发的具体表现形态切换现象(`bptr->show()`). ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值