可以在运行时找到虚函数而不调用吗?

时间:2016-01-27 22:06:09

标签: c++ virtual

我有一个基类Base,有许多派生类(例如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();
}

5 个答案:

答案 0 :(得分:1)

根据您的描述,您似乎有一个设计问题。您考虑过使用template method design patter吗?我们的想法是让您的基类实现通用功能,并通过虚函数实现派生类中的细节。

答案 1 :(得分:1)

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

#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

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

答案 2 :(得分:1)

不,它不可能。 C ++不支持这种内省。 __PRETTY_FUNCTION__就是你要去的所有。

答案 3 :(得分:0)

好吧,除了将宏包装在另一个更小/更短/更多的宏中之外,没有什么可以为你提供一个函数的名称。

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

这也意味着您可以轻松打开/关闭跟踪:

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

(您可能希望将其包含在do { ... } while(0)的两边以避免出现问题,如果您要将WHERE置于if或某些内容中,并且仍然希望它在以下情况下正常工作它&#34;什么都不是&#34;)

答案 4 :(得分:0)

最简单的答案是,由于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();
  }
};

如果您希望日志捕获实际的虚拟(功能名称,文件,行号等)的确切标识,则没有解决方法;样板必须进入功能。

硬壳旧的预处理器可以提供帮助。例如。头脑简单的插图:

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

然后你就有了

LOG;

在函数的开头。