为什么我可以静态调用实例函数?

Why can I call instance functions statically?

我最近在 GitHub 上查看 Notepad++ 源代码,came across 一个这样的方法调用:

Window::init(hInst, parent);

我搜索了它所引用的函数,发现了 Window class- 但是 init 函数被标记为 virtual,很明显它是non-static。以为我犯了一个错误,我检查了整个 header 以确保没有 init 的静态重载,并且我确保没有 Window.cpp 文件。没有。

在查看源代码 15 分钟后,我在本地 git cloned 放弃了 repo,以便我可以在 Visual Studio 中打开它。我做的第一件事就是构建,只是为了确保这不是代表项目开发人员的意外合并——构建成功了。

我采取的后续步骤:

TL;DR: 不知何故,Notepad++ 源代码静态调用了一个 non-static 方法,然后构建。不适用于任何其他 class。证明 here and here.

我已经花了 2 个小时盯着这个看,但我仍然不明白这怎么可能。我错过了什么吗?

不,它没有调用静态函数。它只是调用基础 class 的 init() 版本。基本上,在 tClassName::f 中,你问的是 "I want to call that specific version of the virtual function f() in class tClassName".

通常,在派生 class 中调用基 class 虚函数的对应项是很常见的。例如,工厂方法模式:

#include "tObject.h"
#include "tObject1.h" // public inheritance from tObject
#include "tObject2.h" // public inheritance from tObject
#include "tObject3.h" // public inheritance from tObject

class BaseFactory
{
public:
   // factory method
   virtual tNode *createObject(int id)
   {
      if (id == 1) return new tObject1;
      else return new tObject2;
   }
};

class DerivedFactory: public BaseFactory
{
public:
   virtual tNode *createObject(int id)
   {
      // Overrides the default behavior only for one type
      if (id == 1) return new tObject3;
      // Call the default factory method for all other types
      else return BaseFactory::createObject(id);
   }
};

Am I missing something?

是 - 上下文。 Notepad_plus_Window 派生自 Window,对 Window::init() 的调用在 Notepad_plus_Window::init() 方法内部:

class Notepad_plus_Window : public Window { 
public: 
    ...
    void init(HINSTANCE, HWND, const TCHAR *cmdLine, CmdLineParams *cmdLineParams); 
    ...
};

void Notepad_plus_Window::init(HINSTANCE hInst, HWND parent, const TCHAR *cmdLine, CmdLineParams *cmdLineParams) 
{ 
    ...
    Window::init(hInst, parent); 
    ...
}

在此上下文中,Notepad_plus_Window 正在调用 class Window 版本的 init()

也许这会让您感到困惑。你缺少上下文,这不是你自己的错。

您没有在调用中看到隐含的 this

举个例子:

#include <cstdio>
#include <iostream>

class Foo {
public:
  virtual void bar() {
    std::cout << "Foo" << std::endl;
  }
};

class Bar : public Foo {
public:
  virtual void bar() {
    std::cout << "Bar" << std::endl;
  }
};

int main() {
  Bar bar;
  bar.bar();        //-> bar
  bar.Foo::bar();   //-> foo

  Bar *barp = &bar;
  barp->bar();      //-> bar
  barp->Foo::bar(); //-> foo

  return 0;
}

在上面,我们可以在class'层次结构中指定调用特定方法的对象。

这不是静态函数。它正在调用具有指定 (class) 作用域的函数。

默认情况下,init() 将匹配当前 class 范围内的函数(如果存在)。这是一个隐含的 this 调用,等于 this->init(),

但是使用指定的 class/namespace 前缀,您可以在没有动态绑定的情况下显式调用任何特定函数。即 ::init() 将在全局范围内调用 init() 函数。

下面的代码或许能让你更好的理解

#include <iostream>

class A
{
public:
  virtual void  test()
  {
      std::cout << "A" << std::endl;
  }
};

class B : public A
{
public:
    virtual void test()
    {
        std::cout << "B" << std::endl;
    }
};

int main()
{
    A* a = new B();
    a->A::test();
    return 0;
}