【问题标题】:Is this dynamic or static binding?这是动态绑定还是静态绑定?
【发布时间】:2014-05-08 13:07:23
【问题描述】:

以下是静态绑定还是动态绑定?既然我知道,我的指针在编译时指向的对象类是什么,我的猜测是它是静态的......

class Base 
{
void print() const;
};

class Derived : public Base 
{
void print() const;
};

int main()
{
Base base;
Base *basePtr = &base;
basePtr->print();
}

为什么我们应该使用动态绑定而不是静态绑定?我不明白为什么我们应该使用虚函数而不是简单地以这种方式调用函数base.print()(对于上面的示例)。该方法已经“理解”了哪个print() 函数调用了对象的正确类,而无需使用多态性和虚函数。


更新

  // Point class definition represents an x-y coordinate pair.
  #ifndef POINT_H
  #define POINT_H

  class Point {

  public:
     Point( int = 0, int = 0 ); // default constructor

   void setX( int );  // set x in coordinate pair
   int getX() const;  // return x from coordinate pair

   void setY( int );  // set y in coordinate pair
   int getY() const;  // return y from coordinate pair

   virtual void print() const;  // output Point object

private: 
   int x;  // x part of coordinate pair
   int y;  // y part of coordinate pair

}; // end class Point

#endif

  // Circle class contains x-y coordinate pair and radius.
  #ifndef CIRCLE_H
  #define CIRCLE_H

  #include "point.h"  // Point class definition

  class Circle : public Point {

public:

   // default constructor
   Circle( int = 0, int = 0, double = 0.0 );  

   void setRadius( double );   // set radius
   double getRadius() const;   // return radius

   double getDiameter() const;       // return diameter
   double getCircumference() const;  // return circumference
   double getArea() const;           // return area

   virtual void print() const;       // output Circle object

private: 
   double radius;  // Circle's radius

}; // end class Circle

#endif 

  // Introducing polymorphism, virtual functions and dynamic
  // binding.
  #include <iostream>

  using std::cout;
  using std::endl;
  using std::fixed;

#include <iomanip>

using std::setprecision;

#include "point.h"   // Point class definition
#include "circle.h"  // Circle class definition

int main()
{
   Point point( 30, 50 );
   Point *pointPtr = 0;

   Circle circle( 120, 89, 2.7 );
   Circle *circlePtr = 0; 
  // set floating-point numeric formatting
   cout << fixed << setprecision( 2 );

   // output objects point and circle using static binding
   cout << "Invoking print function on point and circle "
        << "\nobjects with static binding "
        << "\n\nPoint: ";
   point.print();         // static binding
   cout << "\nCircle: ";
   circle.print();        // static binding

   // output objects point and circle using dynamic binding
   cout << "\n\nInvoking print function on point and circle "
        << "\nobjects with dynamic binding";

   // aim base-class pointer at base-class object and print
   pointPtr = &point;                                      
   cout << "\n\nCalling virtual function print with base-class"
        << "\npointer to base-class object"
        << "\ninvokes base-class print function:\n";
   pointPtr->print();
   // aim derived-class pointer at derived-class
   // object and print                          
   circlePtr = &circle;                         
   cout << "\n\nCalling virtual function print with "
        << "\nderived-class pointer to derived-class object "
        << "\ninvokes derived-class print function:\n";
   circlePtr->print();

   // aim base-class pointer at derived-class object and print
   pointPtr = &circle;                                        
   cout << "\n\nCalling virtual function print with base-class"
        << "\npointer to derived-class object "
        << "\ninvokes derived-class print function:\n";
   pointPtr->print();  // polymorphism: invokes circle's print
   cout << endl;

   return 0;

} // end main

【问题讨论】:

  • 没有动态绑定。也不清楚为什么有没有使用的派生类的定义。
  • 尝试将main 中的第一行替换为Derived base;,看看调用的是哪个函数。
  • 另外,virtual 对于基类中的析构函数非常重要。
  • @tillaert 为什么?你能解释一下吗?
  • @user3379939 看到这个问题:stackoverflow.com/questions/461203/…

标签: c++ binding polymorphism


【解决方案1】:

以下是静态绑定还是动态绑定?

静态的,因为函数不是虚拟的。

如果是虚函数,则根据对象的动态类型调度函数。

为什么我们应该使用动态绑定而不是静态绑定?

当我们想通过一个公共基类与不同类型的对象进行交互时,不知道实际(动态)类型是什么。例如,

class Base 
{
    virtual void print() const;  // add "virtual" to enable dynamic dispatch
};

// This function doesn't know the real (dynamic) type of the object,
// but still calls the correct version of "print".
void print(Base const & base) {
    // If "print" is virtual, then this calls the override for the dynamic type.
    // Otherwise, this calls Base::print.
    base.print();
}

int main() {
    Base base;
    Derived derived;

    print(base);     // calls Base::print
    print(derived);  // calls Derived::print
}

该方法已经“理解”了哪个 print() 函数调用了对象的正确类,而无需使用多态性和虚函数。

确实,如果像您的示例中那样,您已经知道动态类型,那么多态性就没有用了。当你不知道动态类型时,就像我的例子一样。

【讨论】:

  • 哦,谢谢!你说得太清楚了!我想给你+1,但我不能……但是不是“静态的,因为函数不是虚拟的”。有点限制?看看我添加的让我如此困惑的程序。我不明白为什么 point.print(); 例如是静态绑定,而 pointPtr-&gt;print(); 是动态...
  • @user3379939: point.print() (可能)被静态调用,因为point 的动态类型已知为Point - 不需要动态调度。 pointPtr-&gt;print() 可能会被动态调用,因为编译器可能不够聪明,无法确定动态类型。无论如何,无论编译器是否决定使用动态调度,结果都是一样的。
【解决方案2】:

您的示例中没有任何动态绑定。您只需定义一个基类类型的指针,并为其分配一个(相同)基类对象的地址。所以不清楚你为什么说动态绑定。

这里也没有用到派生类的定义。

当指针或引用的静态类型与其动态类型不一致并且使用虚函数时,使用动态绑定。 在您的示例中,没有第一个要求,也没有第二个要求。

这里是一个动态绑定的例子

#include <iostream>

class Base 
{
   virtual void print() const { std::cout << "Base" << std::endl; }
   virtual ~Base() = default;
   // or virtual ~Baae() {}
};

class Derived : public Base 
{
   void print() const { std::cout << "Derived" << std::endl; }
};

int main()
{
   Derived d;
   Base *basePtr = &d;
   basePtr->print();
}

虽然指针 basePtr 的静态类型是 Base *,但它的动态类型是 Derived *,因为它是由派生类的对象的地址分配的。

引用 C++ 标准中的注释会更清楚

[ 示例:如果一个指针 (8.3.1) p 其静态类型为“pointer to B 类”指向 D 类的对象,该对象派生自 B(从句 10),表达式*p的动态类型是“D”。参考文献 (8.3.2) 被同样对待。 ——结束示例]

【讨论】:

    【解决方案3】:

    使用virtual 方法时会发生动态绑定。 Base::print 不是 virtual。动态绑定的想法是在运行时将调用的实际方法绑定,当derived 类覆盖基类中的virtual 方法时会发生这种情况,然后取决于实际对象类(基础/派生),方法被绑定。事实上,在派生类中定义与基类同名的方法会隐藏基类方法,这是一种不好的做法。

    【讨论】:

      猜你喜欢
      • 2016-04-18
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多