【问题标题】:Overloaded functions(virtual/non virtual)重载功能(虚拟/非虚拟)
【发布时间】:2014-05-12 15:20:14
【问题描述】:

我有 4 个重载函数 vfoo(3 个是虚拟的)

我在这里尝试测试几个概念:

  1. 使用虚函数重载
  2. 当派生类实现了自己的重载函数版本时,重载函数隐藏在派生类中。
  3. 基类指针存储派生类对象时的行为是什么
  4. 派生类中的重载函数,如 void vfoo(char x)
#include<iostream>
using namespace std;

/*Base class having 4 overloaded function*/  
class ClassBaseV 
{
    public:

        virtual void vfoo( int x ) {
                cout << "ClassBaseV vfoo(int), x = " << x << endl;
        }

        virtual void vfoo( double x ) {
                cout << "ClassBaseV vfoo(double), x = " << x << endl;
        }

        virtual void vfoo( int x, double y ) {
                cout << "ClassBaseV vfoo(int,double), x = " << x << ", y = " << y << endl;
        }

        void vfoo( double x, int y ) {
                cout << "ClassBaseV vfoo(double,int), x = " << x << ", y = " << y << endl;
        }
};


class ClassDerived1 : public ClassBaseV 
{
    public:

        //Overloaded with char x
        void vfoo( char x ) {
                cout << "ClassDerived1 vfoo(char), x = " << x << endl;
        }


         //over riding int x
         void vfoo( int x ) {
                cout << "ClassDerived1 vfoo(int), x = " << x << endl;
        }


};


int main()
{
    ClassBaseV *cB = new ClassDerived1(); /*Base pointer storing derived class object*/
    ClassDerived1 *cd1 = new ClassDerived1(); //Derived class object  
    cd1->vfoo('a');//Direct call using derived class object. this works
    char a = 'a';
    cB->vfoo(a);   // trying to call char x using cB. This calls derived class int How?
    cB->vfoo(10);  // trying to call int x using CB. This calls derived class int 
    cB->vfoo(2.2); // Wanted this to not to work as base class overloaded functions are hidden but this works

    return 1;
}

【问题讨论】:

  • 输出 ClassDerived1 vfoo(char), x = a ClassDerived1 vfoo(int), x = 97 ClassDerived1 vfoo(int), x = 10 ClassBaseV vfoo(double), x = 2.2
  • 如果你实现了重载集的某些功能,通常的做法是添加一个 using 声明,让其他功能进入作用域。避免令人尴尬的使用失败...

标签: c++


【解决方案1】:

第一个问题:

cB->vfoo(a);

当你在这里调用 vfoo 时,它会尝试在 ClassBaseV 中找到 vfoo(char x) 的定义,但它没有,但仍然找到可以隐式转换为的 vfoo(int x) 的定义,所以它从 ClassBaseV 调用此方法。

编译器将尝试获取作为类型提供的类的方法定义。

ClassBaseV *cB = new ClassDerived1();

在这一行中,键入 cB 作为指向 ClassBaseV 的指针。从现在开始,编译器不能查找方法定义的缺点(在子类中),但仍然可以查找优点,因为 ClassBaseV 知道对父类的任何可能继承。

第二个问题:

cB->vfoo(2.2);

在这一行中,您调用方法 vfoo(double x ),因为在 ClassBaseV 中可以转换为 double,并且您不会在 ClassDerived1 中覆盖此方法。

因此,调用此方法的 ClassBaseV 实现是正常行为。

如果您想调用 ClassDerived1 中覆盖的 vfoo 之一,您必须将其转换为 int 或 char(以及松散信息)

cB->vfoo(static_cast<int>(2.2));

或在 ClassDerived1 中添加一个新方法,覆盖 ClassBaseV 中的 vfoo(double x )。

另外,如果你想强制 ClassDerived1 实现来自 ClassBaseV 的方法 vfoo(double x),你必须将它声明为纯虚拟:

virtual void vfoo( double x ) = 0;

【讨论】:

    【解决方案2】:

    “基类指针存储派生类对象时的行为是什么”——这就是多态性的核心思想。 多态性基于运行时中确定的对象类型的特定行为,而重载函数在编译时中解决。

    常量字面量的类型在编译时可以很容易地确定10int2.2double,这将确定将使用哪个成员函数。然后实例的类型将确定将使用哪个实现(哪个类)。这是一个更简单的例子:

    class Animal {
    public:
        virtual void makeSound(){ std::cout << "hi" << std::endl; }
        virtual void makeSound(int pain){ std::cout << "ouch" << std::endl; }
        virtual void makeSound(double d){ std::cout << "aaaaaaaargh" << std::endl; }
    };
    
    class Cat : public Animal {
    public:
        virtual void makeSound(){ std::cout << "meow" << std::endl; }
        virtual void makeSound(int pain){ std::cout << "MEEEEEOW!!!" << std::endl; }
        virtual void makeSound(double d){ std::cout << "meow double" << std::endl; }
    };
    
    int main() {
        Animal *a = new Animal();
        Animal *cat = new Cat();
        a->makeSound();
        cat->makeSound();
        a->makeSound(100);
        cat->makeSound(100);
        cat->makeSound(750.80);
    }
    

    输出:



    哎哟
    喵喵!!!
    喵双

    【讨论】:

      【解决方案3】:

      如果您覆盖派生类中的部分重载集,通常的做法是使用usingdeclaration 将所有未覆盖的函数纳入范围。避免令人尴尬的失败。

      cB->vfoo(a);   // trying to call char x using cB. This calls derived class int How?
      

      Base 中的重载解析得到最接近的匹配 (char -> int) 并使用虚拟调度调用

      cB->vfoo(10);  // trying to call int x using CB. This calls derived class int 
      

      在 ovrload 解析和虚拟调度中执行匹配到派生。

      cB->vfoo(2.2); // Wanted this to not to work as base class overloaded functions are hidden but
      

      重载决议的精确匹配,虚拟分派到基地。

      永远不要尝试删除派生类中的特性。

      接口继承的意思是:我最多需要保障基础需求,我的行为符合基础契约。

      【讨论】:

        猜你喜欢
        • 2019-02-21
        • 1970-01-01
        • 2020-06-05
        • 2016-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多