【问题标题】:When I call a function in child class it is instead calling the parent class function当我在子类中调用函数时,它是在调用父类函数
【发布时间】:2019-04-24 22:55:45
【问题描述】:

我正在开展一个项目,其中有一系列儿童课程。 我想从数组中调用一个被覆盖的子函数,但它却调用了父函数。

#include <iostream>

class Parent {
public:
    Parent(){}
    void print() {
        std::cout << "I'm the parent!" << std::endl;
    }
};

class ChildOne : public Parent {
public:
    ChildOne(){}
    void print() {
        std::cout << "I'm childOne!" << std::endl;
    }
};

class ChildTwo : public Parent {
public:
    ChildTwo() {}
    void print() {
        std::cout << "I'm childTwo!" << std::endl;
    }
};


int main(int argc, char const *argv[]) {
    Parent arr[] = {ChildOne(), ChildTwo()};
    int n = 2;

    for(int i = 0; i < n; i++) {
        arr[i].print();
    }

    return 0;
}

我得到的输出是

I'm the parent!
I'm the parent!

我想要的输出在哪里

I'm childOne!
I'm childTwo!

【问题讨论】:

    标签: c++ c++11 inheritance overriding


    【解决方案1】:

    当您将所有实例存储在该类型化数组中时,您将它们隐式转换为类型 Parent。由于您使用的是静态调度,因此您总是会在您(隐式)向下转换为的基类型上调用该方法。

    【讨论】:

    【解决方案2】:

    首先Parent的成员函数需要是virtual。

    class Parent
    {
       public:
           Parent(){}
           virtual void print() {std::cout << "I'm the parent!" << std::endl;};
    };
    

    然后孩子们需要覆盖它。在 C++11 及更高版本中,建议使用override

    class ChildOne : public Parent
    {
       public:
          ChildOne(){}
          void print() override {std::cout << "I'm childOne!" << std::endl;};
    };
    

    要解决的第二件事是main()中的代码

    Parent arr[] = {ChildOne(), ChildTwo()};
    

    通过切片初始化两个Parent对象,即arr[0]和arr[1]都是Parent类型,而不是ChildOne或ChildTwo。

    为了解决这个问题,arr 必须是一个指针数组,并相应地进行初始化。

     Parent *arr[] = {new ChildOne(), new ChildTwo()};
    

    后面可以跟

    for(int i = 0; i < 2; i++)
    {
        arr[i]->print();
    }
    
    for(int i = 0; i < 2; i++)    // to avoid a memory leak
    {
        delete arr[i];
    }
    //  don't use elements of `arr` here
    

    更好的方法(C++11 及更高版本)是编写main() 是使用标准头文件&lt;memory&gt; 中的std::unique_ptr)

    std::unique_ptr<Parent> arr[] = {new ChildOne(), new ChildTwo()};
    

    这允许取消循环以释放arr 的元素。在 C++14 及更高版本中,arr 中的对象可以使用std::make_unique() 创建。

    【讨论】:

      【解决方案3】:

      您的代码存在两个问题:

      1. 您实际上根本没有覆盖print(),因为它不是virtual。所以你只是在每个子类中重载它,隐藏父类的方法。

      2. 当您将它们存储到您的阵列中时,您是slicing your objects。因此,print() 是否为虚拟并不重要,因为数组中没有子对象,只有父对象。多态性只有在使用基类的指针/引用时才能正常工作。

      试试这个:

      #include <iostream>
      
      class Parent {
      public:
          Parent(){}
          virtual void print() {
              std::cout << "I'm the parent!" << std::endl;
          }
      };
      
      class ChildOne : public Parent {
      public:
          ChildOne(){}
          void print() override {
              std::cout << "I'm childOne!" << std::endl;
          }
      };
      
      class ChildTwo : public Parent {
      public:
          ChildTwo() {}
          void print() override {
              std::cout << "I'm childTwo!" << std::endl;
          }
      };
      
      int main() {
          ChildOne c1;
          ChildTwo c2;
          Parent* arr[] = {&c1, &c2};
      
          int n = 2;
          for(int i = 0; i < n; i++) {
              arr[i]->print();
          }
      
          return 0;
      }
      

      【讨论】:

        【解决方案4】:

        您需要将父函数指定为virtual,子函数应使用override 关键字。

        class Parent {
        public:
            Parent(){}
            virtual void print() {
                std::cout << "I'm the parent!" << std::endl;
            }
        };
        
        class ChildOne : public Parent {
        public:
            ChildOne(){}
            void print() override {
                std::cout << "I'm childOne!" << std::endl;
            }
        };
        
        class ChildTwo : public Parent {
        public:
            ChildTwo() {}
            void print() override {
                std::cout << "I'm childTwo!" << std::endl;
            }
        };
        

        【讨论】:

        • OP 的代码在填充数组时会遭受“对象切片”的影响,因此这只是需要修复的一部分。数组也需要修复。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-27
        • 1970-01-01
        • 1970-01-01
        • 2020-08-10
        • 1970-01-01
        • 2019-05-10
        • 1970-01-01
        相关资源
        最近更新 更多