【问题标题】:Calling methods on class pointers [duplicate]在类指针上调用方法[重复]
【发布时间】:2013-12-31 07:37:54
【问题描述】:

不是我有问题,而是我发现以下事实很奇怪。

/* Class Shape */
class Shape
{
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};


/* Class Triangle */
class Triangle: public Shape
{
   public:
      Triangle( int a=0, int b=0)
      {
        Shape(a, b); 
      }
      int area ()
      { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};

int main( )
{
   Shape *shape;
   Triangle tri(10,7);


   shape = &tri;
   (*shape).area();



   return 0;
}

上面将打印的是:“父类区域:”。

所以编译器似乎没有检查指针内容?并且仅基于指针类型调用方法?否则它会看到 *shape 是一个 Triangle 对象并且会调用三角形版本的 area 不是吗?

ps。我知道你可以使用虚函数让它按照我描述的方式工作,但这不是我现在感兴趣的,只是我发现这种行为有点奇怪,也许我错过了一些东西。

【问题讨论】:

  • 指针内容是运行时的。那不是编译器的工作。编译器的工作是检查语法并将您的程序转换为可以通过链接器链接在一起的目标文件。任何形式的情报,例如知道指针内容和警告您可能正在做一些非法的事情,都是一种附加功能。如果 Shape::area 是虚拟的,它只会调用三角形版本。

标签: c++


【解决方案1】:

您需要在基类中将int area() 标记为virtual,即

virtual int area()
{
    /*etc*/

这告诉编译器建立一个适当的函数表,以便根据指针所指的类型调用正确的 area 函数。

(请注意,在 Java 中,所有非静态函数都是隐式虚函数。)

【讨论】:

  • 这不能回答 OP 的问题(不管它是什么)。他们声称理解使函数虚拟化可以解决“问题”。
  • @ChristopherCreutzig:是的,我知道取消引用会引用原始对象而不是对象本身。对象和对它的引用产生影响的地方,。
  • @juanchopanza:是的。好吧,我认为我的问题来自混淆,因为在我的代码中,函数是基于指针类型而不是它所指的实际对象调用的——我发现这很奇怪。我认为它现在被称为早期绑定,因为我对它进行了更深入的研究(只是最初对我来说有点奇怪)
  • @Uchialtachi 我不明白你的意思。 (*shape).area() 在引用 TriangleShape&amp; 上调用 area。它完全等同于shape-&gt;area(),它(对于普通指针和正确编写的智能指针)只是一个简写符号。
  • @ChristopherCreutzig:我理解并且意思相同。看来我的措辞不够清楚。没关系。
【解决方案2】:

这是因为您并没有真正替换函数,您只是在 Triangle 类中添加了另一个版本。在这个类中,总是可以像这样调用父级的版本

Shape::area();

所以两个版本都需要存在于 Triangle 类中。因为它是一个非虚函数,编译器只是查看类型的名称来确定应该调用可执行文件中的哪个函数(像_ZN5Shape4areaEv 这样的神秘函数)并使用它。

【讨论】:

    【解决方案3】:

    您的main() 函数可以简化为:

    int main()
    {
        Triangle tri(10,7);
        tri.Shape::area();
    }
    

    class Triangle两个 名为 int area() 的函数(一个在基类中,一个在派生类中)。

    int Triangle::area() 将默认为 class Triangle 的对象调用,因为它隐藏 int Shape::area()

    通过在指针上执行(C 风格)强制转换,您是在告诉您的程序从class Shape 调用版本。正如您所说,由于int Shape::area() 不是virtual,因此没有虚拟成员函数表(),因此将调用Shape 版本。

    这是预期的和明确定义的行为。

    示例:

    延伸阅读:

    【讨论】:

    • 这似乎被称为早期绑定代码中发生的事情。由于某些原因,我期望编译器或运行时会查找 *shape 对应于 Triangle 对象并调用 Triangle 的方法,但显然情况并非如此,并且被调用的函数取决于基于指针 @ 的编译时间987654340@.
    猜你喜欢
    • 2011-01-31
    • 2020-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-21
    • 2021-09-27
    相关资源
    最近更新 更多