我最近在GitHub上查看Notepad ++源代码,came across这样的方法调用:
Window::init(hInst, parent);
我搜索了它引用的函数,并遇到Window
类 - 但init
函数标记为virtual
,所以很明显它是非静态的。想到我犯了一个错误,我检查了整个标头,以确保没有init
的静态重载,我确保没有Window.cpp
文件。没有。
在源码周围探索了15分钟之后,我在本地放入了git cloned
repo,因此我可以在Visual Studio中打开它。我做的第一件事就是构建以确保代表项目开发人员不会意外合并 - 构建成功。
我接下来的步骤:
我打开了调用Window::init
的文件,然后点击Go To Declaration
上的Window
。我需要Window
课程。
我在Go To Declaration
函数上点击了init
。它指出了虚拟方法的签名。
我将Window.h
文件复制并粘贴到一个全新的标头中,并将Window
的所有引用替换为Foo
。当我输入Foo::init
时,编译器会抱怨'非静态成员引用必须与特定对象相关'。
TL; DR:不知何故,Notepad ++源代码静态调用非静态方法,并构建此方法。不适用于任何其他类。证明here和here。
我花了2个小时盯着这个,但我仍然没有看到它是如何可能的。我错过了什么吗?
答案 0 :(得分:2)
不,它没有调用静态函数。它只是调用基类的init()
版本。基本上,在tClassName::f
中,您要求"我想在课程f()
"中调用虚拟函数tClassName
的特定版本。
通常,在派生类中调用基类的虚函数副本是很常见的。例如,工厂方法模式:
#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);
}
};
答案 1 :(得分:2)
我错过了什么吗?
是 - 背景。 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
正在调用Window
的基类init()
版本。
答案 2 :(得分:1)
这可能会让你更加困惑。你错过了背景,没有你自己的错误。
您没有在通话中看到隐含的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;
}
在上面,我们可以指定在类的层次结构中调用特定方法的对象。
答案 3 :(得分:1)
这不是静态功能。它正在调用具有指定(类)范围的函数。
默认情况下,init()将匹配当前类范围内的函数(如果它们确实存在)。这是一个隐含的调用,等于this-&gt; init(),
但是使用指定的类/名称空间前缀,您可以显式调用任何特定函数而无需动态绑定。 ie :: 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;
}