为什么我可以静态调用实例函数?
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 中打开它。我做的第一件事就是构建,只是为了确保这不是代表项目开发人员的意外合并——构建成功了。
我采取的后续步骤:
我打开了调用 Window::init
的文件并在 Window
上单击了 Go To Declaration
。它带我到 Window
class.
我在 init
函数上单击了 Go To Declaration
。它指出了虚拟方法的签名。
我将 Window.h
文件复制并粘贴到一个全新的 header 中,并将 Window
的所有引用替换为 Foo
。当我输入 Foo::init
时,编译器会抱怨 'a nonstatic member reference must be relative to a specific object'.
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;
}
我最近在 GitHub 上查看 Notepad++ 源代码,came across 一个这样的方法调用:
Window::init(hInst, parent);
我搜索了它所引用的函数,发现了 Window
class- 但是 init
函数被标记为 virtual
,很明显它是non-static。以为我犯了一个错误,我检查了整个 header 以确保没有 init
的静态重载,并且我确保没有 Window.cpp
文件。没有。
在查看源代码 15 分钟后,我在本地 git cloned
放弃了 repo,以便我可以在 Visual Studio 中打开它。我做的第一件事就是构建,只是为了确保这不是代表项目开发人员的意外合并——构建成功了。
我采取的后续步骤:
我打开了调用
Window::init
的文件并在Window
上单击了Go To Declaration
。它带我到Window
class.我在
init
函数上单击了Go To Declaration
。它指出了虚拟方法的签名。我将
Window.h
文件复制并粘贴到一个全新的 header 中,并将Window
的所有引用替换为Foo
。当我输入Foo::init
时,编译器会抱怨 'a nonstatic member reference must be relative to a specific object'.
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;
}