简体   繁体   English

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

[英]Why can I call instance functions statically?

I was looking around the Notepad++ source code on GitHub recently, and came across a method call like this: 我最近在GitHub上查看了Notepad ++源代码,并遇到了这样的方法调用:

Window::init(hInst, parent);

I searched for the function it was referencing to, and came across a Window class- but the init function was marked virtual , so clearly it was non-static. 我搜索了它引用的函数,并遇到了一个Window类 - 但是init函数被标记为virtual ,所以很明显它是非静态的。 Thinking I made a mistake, I checked the entire header to make sure there was no static overload of init , and I made sure there was no Window.cpp file. 认为我犯了一个错误,我检查了整个标头,以确保没有init静态重载,我确保没有Window.cpp文件。 There isn't. 没有。

After poking around the source for 15 more minutes, I gave in and git cloned the repo locally so I could open it in Visual Studio. 在浏览源15分钟之后,我放弃了并且git cloned在本地git cloned了repo,所以我可以在Visual Studio中打开它。 The first thing I did was to build just to make sure this wasn't an accidental merge on behalf of the project developers- the build succeeded. 我做的第一件事就是构建以确保这不是代表项目开发人员的意外合并 - 构建成功。

The next steps I took: 我接下来的步骤:

  • I opened the the file calling Window::init and clicked Go To Declaration on Window . 我打开调用Window::init的文件,然后单击Window上的Go To Declaration It takes me to the Window class. 它带我到Window类。

  • I clicked Go To Declaration on the init function. 我在init函数上单击了Go To Declaration It points me to the signature of the virtual method. 它指出了虚拟方法的签名。

  • I copy and paste the Window.h file into an entirely new header and replace all references of Window with Foo . 我将Window.h文件复制并粘贴到一个全新的标题中,并用Foo替换Window所有引用。 When I type in Foo::init , the compiler complains that 'a nonstatic member reference must be relative to a specific object'. 当我输入Foo::init ,编译器会抱怨'非静态成员引用必须与特定对象相关'。

TL;DR: Somehow, the Notepad++ source code calls a non-static method statically, and this builds. TL; DR:不知何故,Notepad ++源代码静态地调用非静态方法,并构建它。 Doesn't work with any other class. 不适用于任何其他类。 Proof here and here . 证明在这里这里

I have spent 2 hours staring at this, but I still don't see how it's possible. 我花了2个小时盯着这个,但我仍然没有看到它是如何可能的。 Am I missing something? 我错过了什么吗?

No, it's not calling a static function. 不,它不是在调用静态函数。 It's just calling the base class's version of init() . 它只是调用基类的init()版本。 Basically, in tClassName::f , you are asking "I want to call that specific version of the virtual function f() in class tClassName ". 基本上,在tClassName::f ,您要求“我想在类tClassName调用该特定版本的虚函数f() ”。

Generally, it's pretty common to call the base class's counterpart of a virtual function in the derived class. 通常,在派生类中调用基类的虚函数对应是很常见的。 Eg, the factory method pattern: 例如,工厂方法模式:

#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? 我错过了什么吗?

Yes - context. 是的 - 背景。 Notepad_plus_Window derives from Window , and the call to Window::init() is inside of the Notepad_plus_Window::init() method: 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); 
    ...
}

In this context, Notepad_plus_Window is calling the base class Window version of init() . 在此上下文中, Notepad_plus_Window正在调用init()的基类Window版本。

Maybe this will confuse you less. 也许这会让你更加困惑。 You're missing context, at no real fault of your own. 你错过了上下文,没有你自己的真正错误。

You're not seeing the implicit this in the call. 你没有在通话中看到隐含的this

Take the following example: 请看以下示例:

#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;
}

In the above, we can specify the object on which to call a specific method in the class' hierarchy. 在上面,我们可以指定在类的层次结构中调用特定方法的对象。

It's not a static function. 这不是静态功能。 It's calling a function with a specified (class) scope. 它调用具有指定(类)范围的函数。

By default, init() will match functions within current class scope, if they do exist. 默认情况下,init()将匹配当前类范围内的函数(如果它们确实存在)。 that is an implicit this call, equals this->init(), 这是一个隐式的调用,等于this-> init(),

But with a specified class/namespace prefix, you can explicit call any particular function without dynamic binding. 但是使用指定的类/名称空间前缀,您可以显式调用任何特定函数而无需动态绑定。 ie ::init() will call the init() function within global scope. ie :: init()将在全局范围内调用init()函数。

the following code may give you a better understanding 以下代码可能会让您更好地理解

#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.

相关问题 为什么我可以从子类调用私有函数 - Why can I call private functions from a sub class 如何从另一个仅静态选择满足某种类型规则的索引的元组实例创建一个元组实例? - How can I create a tuple instance from another tuple instance that statically selects only indices that satisfy a certain type rule? 如何从静态分配的对象中调用虚拟函数? - How to call virtual functions from statically allocated objects? 为什么我不能从C ++中的派生类实例调用模板化方法? - Why can't I call a templated method from a derived class instance in C++? 为什么我不能从C ++中该类的实例调用该类的构造函数? - Why can I not call my class's constructor from an instance of that class in C++? 为什么我不能直接调用由指向成员的指针访问的实例的方法 - why can't I directly call a method of an instance which is accessed by pointer-to-member 在gdb中,我可以调用一些类函数,但其​​他函数“无法解析”。 为什么? - In gdb, I can call some class functions, but others “cannot be resolved”. Why? 当一个结构有c-tor时,为什么我不能静态初始化它呢? - when a structure has c-tor, why can't I statically initialize it? 我可以静态地将MSVCRT与mingw链接吗? - Can I link MSVCRT statically with mingw? 什么时候编译器可以静态绑定对虚函数的调用? - When can the compiler statically bind a call to a virtual function?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM