【问题标题】:call a childs version of a function instead of a parents?调用函数的子版本而不是父母?
【发布时间】:2011-08-04 09:42:35
【问题描述】:

好的,所以我有两节课。

class a{
public:
a(){};
void print(){cout << "hello"};
}

class b : public a{
public:
void print(){cout << "hello world";}
}

还有一群带着孩子的父母

a blah[10];
blah[5] = b();

我打电话给 print,并希望它向世界打招呼。

blah[5].print();

但它调用父级。我该如何解决这个问题?

【问题讨论】:

    标签: c++ inheritance virtual overriding


    【解决方案1】:

    a::print() 声明为虚拟并使用指针/引用 调用print() 函数。当您执行blah[5] = b() 时,它会进行对象切片。使用对象调用虚函数没有任何效果。

    【讨论】:

      【解决方案2】:

      这可以通过声明函数 virtual 来解决,比如:

      class a{
      public:
          virtual void print(){
              cout << "hello";
          }
      }
      
      class b : public a{
      public:
          virtual void print() {
              cout << "hello world";
          }
      }
      

      这就是在 C++ 中实现多态性的方式。更多内容:http://en.wikipedia.org/wiki/Virtual_function

      但是,应该注意的是,在您的示例中,它永远不会调用子函数,因为您使用的是对象,而不是对象的指针/引用。为了解决这个问题,

      a * blah[10];
      blah[5] = new b();
      

      然后:

      blah[5]->print();
      

      【讨论】:

        【解决方案3】:

        这样做是因为您告诉编译器您的实例是a 类型。它在a 对象的数组中,对吗?所以它的类型是a

        当然,您希望b 中的方法覆盖a 中的方法,尽管有父类型的引用。您可以在父类的函数声明中使用 virutal 关键字来获得该行为。

        virtual void print(){cout << "hello"};
        

        为什么会这样?

        因为当您将对象转换为父类时,您引入了歧义。当这个对象的print()被调用时,我们应该如何对待呢?它的类型为b,但引用的类型为a,因此环绕代码可能期望它的行为类似于a,而不是b

        为了消除歧义,引入了virtual 关键字。 virtual 函数总是被覆盖,如果对象属于包含具有相同签名的方法的子类。

        干杯!

        【讨论】:

          【解决方案4】:

          您正在寻找的是运行时多态性,这意味着让对象采用“多种形式”(即 a 或 b),并在程序运行时采取相应的行动。在 C++ 中,您可以通过在基类 a 中创建函数 virtual 来做到这一点:

          virtual void print() {cout << "hello"}; 
          

          然后,您需要通过指针或引用来存储元素,并且 - 通常派生类可以引入新的数据成员并需要更多存储空间 - 在堆上使用 new 创建对象是正常的:

          a* blah[10];
          blah[5] = new b();
          

          然后你可以调用:

          blah[5]->print();  
          

          它会调用print()b实现。

          你应该稍后delete blah[5](以及你指向new返回的内存的任何其他人)。

          在实践中,最好使用一个容器,该容器可以在其自身被破坏时删除它所包含的对象,无论是由于离开范围还是被删除。 std::vector&lt;&gt; 就是这样一个容器。您还可以使用智能指针自动删除ab 对象。如果在您的 delete 语句执行之前抛出异常,并且您希望程序继续运行而不会泄漏内存,这有助于使代码正确。 boost 库是从中获得智能指针实现的最简单/最佳的地方。一起:

          #include <vector>
          #include <boost/shared_ptr.hpp>
          
          std::vector<boost::shared_pointer<a> > blah(10);
          
          blah[5] = new b();
          

          (将向量与push_back() 一起使用更为正常,因为它会自动增大向量以适应您添加的所有元素,并通过调用vector::size() 获得新的总数。)

          【讨论】:

            猜你喜欢
            • 2022-12-04
            • 2020-05-13
            • 1970-01-01
            • 2011-08-25
            • 2011-11-09
            • 1970-01-01
            • 2011-08-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多