c++函数重载二义性

  • 例一:
    #include <stdio.h>
    void f(int a);
    void f(long a);
    void f(char a);

    int main(int argc,char *argv[])
    {
     double value = 65.01;
     f(value);
     return 0;
    }

    void f(int a)
    {
     printf("int value=%d/n", a);
    }
    void f(long a)
    {
     printf("long value=%d/n", a);
    }
    void f(char a)
    {
     printf("char value=%c/n", a);
    }
    编译上面的代码,出现如下错误:
    error C2668: “f” : 对重载函数的调用不明确
    在 f(value);调用中,由于存在隐式数据转换为,value自动转换成整形值65,但是char,int,long都属于整型,编译器不知道该调用f(char),f(int),还是f(long),由于程序运行路径具有可预知的唯一路径,编译器不能帮程序设计者决定使用那个函数,所以不能通过编译。
  • 例二:
    #include <stdio.h>
    void f(int a);
    void f(long a);
    void f(char a);

    int main(int argc,char *argv[])
    {
     double value = 65.01;
     f(static_cast<int>(value));
     f(static_cast<char>(value));
     f(static_cast<long>(value));
     return 0;
    }

    void f(int a)
    {
     printf("int value=%d/n", a);
    }
    void f(long a)
    {
     printf("long value=%d/n", a);
    }
    void f(char a)
    {
     printf("char value=%c/n", a);
    }
    上面的程序由于使用了static_cast进行了明确的类型转换,编译器知道程序将调用哪一个函数,所以能正确运行。
  • 总结
    如果在程序中涉及到函数重载,相同位置上的参数如果是char,short,int,long,unsigned short,unsigned int,unsigned long,unsigned char,那么可能会引起二义性,应该多加注意,在调用函数的地方一定要进行显示的类型转换。
  • 例三
    #include <stdio.h>

    class Base
    {
    public:
     void f(int a){printf("Base f:para=%d/n", a);}
    };
    class Derived: public Base
    {
    public:
     void f(long a){printf("Derived f:para=%d/n", a);}
    };

    int main(int argc,char *argv[])
    {
     Derived d;
     Base &b = d;
     d.f(1);
     b.f(1);
     return 0;
    }
    这个程序可以成功通过编译,并运行吗?答案是肯定的,因为Derived中f函数是重新定义,不是重载,由于函数f不是虚函数,那么调用f函数的时候,将来根据对象的静态类型来调用对应类的函数.
    d.f(1);由于d的静态类型是Derived ,所以将调用Derived::f(long a)函数;
    b.f(1);由于B的静态类型是Base,所以将调用Base::f(int a)函数;
    运行结果:
    Derived f:para=1
    Base f:para=1
  • 例四
    #include <stdio.h>
    class Base
    {
    public:
     virtual void f(int a){printf("Base f:para=%d/n", a);}
    };
    class Derived: public Base
    {
    public:
     virtual void f(long a){printf("Derived f:para=%d/n", a);}
    };

    int main(int argc,char *argv[])
    {
     Derived d;
     Base &b = d;
     d.f(1);
     b.f(1);
     return 0;
    }
    这个程序有问题吗?答:没有问题,能正确运行;
    由于在Derived重新定义了f函数,覆盖了Base的f,并没有重新实现虚函数,所以d.f(1);调用Derived中重新定义的函数没有问题;
    b.f(1);由于b的静态类型为Base,调用Base::f(int a)也是没有疑问的,所以运行结果和上例一样:
    Derived f:para=1
    Base f:para=1
    总结,如果在子类中,重新定义了虚拟函数,或者重载了基类虚函数,那么将覆盖从子类继承来的同名虚函数,那么在调用函数的时候,将根据对象的静态类型来决定调用那个函数.
  • 例五

    int main(int argc,char *argv[])
    {
     Derived d;
     Base &b = d;
     
     double value = 87.01;
     d.f(value);
     b.f(value);
     return 0;
    }
    编译的时候,将会在d.f(value);报错误:error C2668: “Derived::f” : 对重载函数的调用不明确,二义性就如第一个例子那样产生了.因为value在这里不知道该转换成int还是long;
    但是b.f(value);调用没有二义性,因为在Base空间只有一个f函数,虽然有警告,单在这个地方value只能转换成int类型,确定会调用Base::f(int a),所以编译器不会报错误.

    在这儿,由于f(int)在子类中被重新定义,在Derived中重载了f(long),所以在这儿就存在了二义性.

    在子类中千万不要随便重新定义基类继承过来的虚函数,造成基类继承下来的虚函数被覆盖.

你可能感兴趣的:(C++,c,Class,编译器)