多态的整体认识

  这里插播一则对于多态的认识,多态是面相对相三巨头之一(封装,继承,多态),而且还是其中最神秘的一个。对于刚刚步入编程大门的人,他的很多故事都鲜为人知。想要想要了解他为何能成为三巨头之一,就要先看看他的一众小弟,重载,重写,隐藏,虚函数,接下来让我们好好了解一下他们。

1.重载(最老实的小弟)

(1)范围:在同一作用域中,也就是在同一个类中或同一源文件中;
(2)函数名:函数名必须相同;
(3)参数:参数类型,参数个数,参数顺序中至少有一项不同;
(4)返回值类型:不影响,可以相同,可以不同。
(5)关键字修饰:被const或volatile关键字修饰不同的也会重载,这是一种常被人遗忘的重载方式。
(6)virtual关键字可有可无。

class A
{ 
    void func(int i) {......} //函数 

    void func(char c) {......} //函数的重载

    void func(int i, char c) {......} //函数的重载

    void func(char c, int i) {......} //函数的重载

    void func(int i) const {......} //函数的重载 
}; 

  之所以说他是多态手下最老实的小弟了,是因为他从不出门,只在家里晃悠,也就是只有在同一作用域里的函数会发生重载。再者重载始终如一,不像他的其他朋友那么机灵善变。当程序编译时编译器会以作用域+返回类型+函数名+参数列表的形式将其重新命名。之后这个名字就再也没法改变了,重载的使命也就完成了。当我们调用函数时写入不同类型的参数或关键字时,程序会自动调用不同的函数。

#include<iostream>

using namespace std;

class A
{ 
    public:
        void func(int i)
        {
            cout<<i<<endl;
        } 

        void func(char c)
        {
            cout<<c<<endl;
        } 

        void func(int i, char c)
        {
            cout<<i<<"  "<<c<<endl;
        } 

        void func(char c, int i)
        {
            cout<<c<<"  "<<i<<endl;
        } 

        void func(int i) const 
        {
            cout<<i<<"  "<<i<<endl;
        } 
}; 

int main()
{
    A a;
    const A aa;
    a.func(1);
    a.func('A');
    a.func(1,'A');
    a.func('A',1);
    aa.func(1);

    return 0;
}

输出结果:

1
A
1  A
A  1
1  1

2.覆盖(又名重写,好动,虚函数的好兄弟):

(1)范围:不同作用域,只在继承中,分别位于基类和派生类中;
(2)要求:基类中函数必须加virtual;
(3)函数:派生类中的函数必须要与基类中的完全相同(函数名,返回值类型,参数列表)。
(4)重写函数的访问修饰符可以不同。尽管 virtual 是 private 的,派生类中重写改写为 public,protected 也是可以的。

class A
{

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

class B:public A
{
    public:
        void func()
        {
            cout<<"B"<<endl;
        }
};

  只要基类指针(要用指针调用才能体现)指向哪个类,就会调用哪个类中的函数,所以它很不消停。这也正是他多态的体现。重写是一定要基于虚函数才能实现的,所以虚函数和重写是一对好兄弟,形影不离。

#include <iostream>

using namespace std;

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

class B:public A
{
    public:
        void func()
        {
            cout<<"B"<<endl;
        }
        ~B(){};
};

int main()
{
    A *a=new A;
    a->func();
    delete a;
    a=new B;
    a->func();
    delete a;
    return 0;
}

输出结果:

A
B

3.重定义(又名隐藏)

(1)范围:不同作用域中,基类与派生类中;
(2)函数名:函数名必须相同;
(3)返回值可以不同;
(4)参数不同时,不论有无 virtual 关键字,都为隐藏。
(5)参数相同,但是基类函数没有 virtual关键字这也是隐藏。

#include<iostream>

using namespace std;

class A
{
    public:
        virtual int func1()
        {
            cout<<"A::func1"<<endl;
        }
        int func2(float y)
        {
            cout<<"A::func2"<<","<<y<<endl;
        }
        virtual ~A(){};
};

class B:public A
{
    public:
        int func1()
        {
            cout<<"B::func1"<<endl;
        }
        int func2(int x,float y)
        {
            cout<<"B::func2"<<","<<y<<endl;
        }
        ~B(){};
};

int main()
{

    int i=1;
    float f=1.1;
    A a;
    B b;
    cout<<"-----------pa=a"<<endl;
    A *pa=&a;
    pa->func1();
    pa->func2(f);
    cout<<"-----------pa=b"<<endl;
    pa=&b;
    pa->func1();
    pa->func2(f);
    cout<<"-----------pb=a"<<endl;
    B *pb=(B *)&a;//强制类型转化
    pb->func1();
    pb->func2(i,f);
    cout<<"-----------pb=b"<<endl;
    pb=&b;
    pb->func1();
    pb->func2(i,f);

    return 0;
}

输出结果:

-----------pa=a
A::func1
A::func2,1.1
-----------pa=b
B::func1
A::func2,1.1
-----------pb=a
A::func1
B::func2,1.1
-----------pb=b
B::func1
B::func2,1.1

  可以看出如果是基类指针(有一般都是),不论指向谁,子类中同名函数会被隐藏,将会调用基类的函数。相反,如果是子类指针,不论指向谁,基类中同名函数会被隐藏,将会调用子类的函数。

总结:

  关于多态网上有着各种各样的说辞,看着让人眼花缭乱,难辨是非。经过我的分析和试验,最终得出了以上结论,如果有什么不对的地方还望指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值