虚函数运行时不调用也能找到吗?

Can the virtual function be found at runtime without calling?

我有一个基础 class Base,其中有许多派生的 class(例如 Derived1Derived2)。 Base 有一个纯虚函数 fn,使用 Base 指针多次调用它。每次调用该函数时,我都需要做一些额外的日志记录和相关工作。特别是,我在 derived-class 函数中使用 BOOST_CURRENT_FUNCTION 来找出调用了哪个函数。有没有办法在调用函数之前知道这些信息,这样我就不必在每个派生函数中重写簿记代码?

编辑:我希望避免在每个派生函数中写 __PRETTY_FUNCTION__

#include <iostream>
using namespace std;

class Base {
public:
virtual void fn() = 0;
};

class Derived1:public Base {
public:
void fn() {
cout<<__PRETTY_FUNCTION__<<endl;
}
};

class Derived2:public Base {
public:
void fn() {
cout<<__PRETTY_FUNCTION__<<endl;
}
};

int main()
{
    int choice =0;
    Base *ptr1 = nullptr;
    cout<<"Choose 0/1: "<<endl;
    cin>>choice;
    if(choice == 0) {    
       ptr1 = new Derived1;
    }else {
       ptr1 = new Derived2;
    }

    //********CAN I WRITE SOMETHING HERE, TO GIVE THE SAME RESULT?
    ptr1->fn();
}

从你的描述来看,你可能有设计问题。您是否考虑过使用 template method design patter?这个想法是让你的基础 class 实现通用功能,并通过虚拟函数在你的派生 classes 中实现细节。

一个想法是实现基本的纯虚函数并在每个派生覆盖中调用它。在基础中,您增加了一个静态计数器。类似于:

#include <iostream>
#include <memory>

struct Base
{
    static size_t counter;
    virtual void f() = 0;
    virtual ~Base() = default;
};
size_t Base::counter{0};

void Base::f() // IMPLEMENTATION, yes it's possible to implement a pure virtual function
{
    ++counter;
}

struct Derived1: Base
{
    void f() override
    {
        Base::f(); // increment the counter
        std::cout << "Derived1::f()\n";
    }
};

struct Derived2: Base
{
    void f() override
    {
        Base::f(); // increment the counter
        std::cout << "Derived2::f()\n";
    }
};

int main()
{
    std::unique_ptr<Base> pBase1{new Derived1};
    std::unique_ptr<Base> pBase2{new Derived2};

    pBase1->f();
    pBase1->f();

    pBase2->f();

    std::cout << Base::counter << std::endl; // outputs 3
}

Live on Wandbox

如果我没记错的话,我相信这是模板方法设计模式的一个实例。没有其他内在方法可以从语言中获取此信息,因为 C++ 没有真正的运行时反射功能。

不,不可能。 C++ 不支持这种内省。 __PRETTY_FUNCTION__ 就是你要得到的。

好吧,除了将您的宏包装在另一个 smaller/shorter/does 的宏中之外,没有任何东西可以为您提供函数名称。

   #define WHERE cout << __PRETTY_FUNCTION__ << endl
   ...
   void fn() {
      WHERE;
   }

这也意味着您可以轻松地 on/off 跟踪:

  #if TRACING
     #define WHERE cout << __PRETTY_FUNCTION__ << endl
  #else
     #define WHERE
  #endif

(如果您将 WHERE 放在 if 或类似的内部,并且仍然希望它正常工作,您可能希望将其包裹在 do { ... } while(0) 两侧以避免出现问题什么时候 "nothing")

最简单的答案是,由于 C++ 没有辅助方法,您必须将 fn 的实现拆分为实用程序包装器和适当的虚函数:

class Base {
protected:
  virtual void fn_impl() = 0;
public:
  void fn() { fn_impl(); }
};

class BaseWithLogging: public Base {
public:
  void fn(); {
    /* do logging */
    fn_impl();
  }
};

如果您希望日志捕获虚拟的确切身份(函数名称、文件、行号,...),这实际上是没有解决方法;样板文件必须进入函数。

老旧的预处理器可以提供帮助。例如。 simple-minded 插图:

#define LOG (cout<<__PRETTY_FUNCTION__<<endl)

然后你就有了

LOG;

在函数的开头。