虚函数运行时不调用也能找到吗?
Can the virtual function be found at runtime without calling?
我有一个基础 class Base
,其中有许多派生的 class(例如 Derived1
、Derived2
)。 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
}
如果我没记错的话,我相信这是模板方法设计模式的一个实例。没有其他内在方法可以从语言中获取此信息,因为 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;
在函数的开头。
我有一个基础 class Base
,其中有许多派生的 class(例如 Derived1
、Derived2
)。 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
}
如果我没记错的话,我相信这是模板方法设计模式的一个实例
不,不可能。 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;
在函数的开头。