[英]Why can I call instance functions statically?
我最近在GitHub上查看了Notepad ++源代碼,並遇到了這樣的方法調用:
Window::init(hInst, parent);
我搜索了它引用的函數,並遇到了一個Window
類 - 但是init
函數被標記為virtual
,所以很明顯它是非靜態的。 認為我犯了一個錯誤,我檢查了整個標頭,以確保沒有init
靜態重載,我確保沒有Window.cpp
文件。 沒有。
在瀏覽源15分鍾之后,我放棄了並且git cloned
在本地git cloned
了repo,所以我可以在Visual Studio中打開它。 我做的第一件事就是構建以確保這不是代表項目開發人員的意外合並 - 構建成功。
我接下來的步驟:
我打開調用Window::init
的文件,然后單擊Window
上的Go To Declaration
。 它帶我到Window
類。
我在init
函數上單擊了Go To Declaration
。 它指出了虛擬方法的簽名。
我將Window.h
文件復制並粘貼到一個全新的標題中,並用Foo
替換Window
所有引用。 當我輸入Foo::init
,編譯器會抱怨'非靜態成員引用必須與特定對象相關'。
TL; DR:不知何故,Notepad ++源代碼靜態地調用非靜態方法,並構建它。 不適用於任何其他類。 證明在這里和這里 。
我花了2個小時盯着這個,但我仍然沒有看到它是如何可能的。 我錯過了什么嗎?
不,它不是在調用靜態函數。 它只是調用基類的init()
版本。 基本上,在tClassName::f
,您要求“我想在類tClassName
調用該特定版本的虛函數f()
”。
通常,在派生類中調用基類的虛函數對應是很常見的。 例如,工廠方法模式:
#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);
}
};
我錯過了什么嗎?
是的 - 背景。 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
正在調用init()
的基類Window
版本。
也許這會讓你更加困惑。 你錯過了上下文,沒有你自己的真正錯誤。
你沒有在通話中看到隱含的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;
}
在上面,我們可以指定在類的層次結構中調用特定方法的對象。
這不是靜態功能。 它調用具有指定(類)范圍的函數。
默認情況下,init()將匹配當前類范圍內的函數(如果它們確實存在)。 這是一個隱式的調用,等於this-> 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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.