Reputation: 1223
I have a base class Base
, with many derived classes (eg. Derived1
, Derived2
). Base
has a pure virtual function fn
, which is called many times using a Base
pointer. Every time the function is called, I need to do some extra logging and related stuff. In particular, I use BOOST_CURRENT_FUNCTION
in the derived-class functions to find out which function was called. Is there a way to know this information before calling the function, so that I do not have to rewrite the bookkeeping code in every derived function?
Edit: I wish to avoid writing __PRETTY_FUNCTION__
in each derived 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();
}
Upvotes: 1
Views: 179
Reputation: 58617
The simplest answer is that, since C++ doesn't have auxiliary methods, you have to split the implementation of fn
into a utility wrapper and the virtual function proper:
class Base {
protected:
virtual void fn_impl() = 0;
public:
void fn() { fn_impl(); }
};
class BaseWithLogging: public Base {
public:
void fn(); {
/* do logging */
fn_impl();
}
};
If you want the logs to capture the exact identity of the virtual (function name, file, line number, ...) which is actually, then there is no workaround for that; the boilerplate has to go into the function.
The crusty old preprocessor can be of help. E.g. simple-minded illustration:
#define LOG (cout<<__PRETTY_FUNCTION__<<endl)
and then you just have
LOG;
at the beginning of the function.
Upvotes: 0
Reputation: 129484
Well, aside from wrapping your macro in another macro that is smaller/shorter/does more, there is nothing that will provide the name of a function for you.
#define WHERE cout << __PRETTY_FUNCTION__ << endl
...
void fn() {
WHERE;
}
This also means you can turn on/off the tracing trivially:
#if TRACING
#define WHERE cout << __PRETTY_FUNCTION__ << endl
#else
#define WHERE
#endif
(You may want to wrap that in do { ... } while(0)
in both sides to avoid problems if you were to put a WHERE
inside an if, or some such, and still want it to work correctly when when it's "nothing")
Upvotes: 0
Reputation: 56567
One idea is to implement the base pure virtual function and call it in each derived override. In the base one you increment a static counter. Something like:
#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
}
If I'm not wrong I believe this is an instance of the Template Method design pattern mentioned by @LordDosias. There is no other intrinsic way of getting this information out from the language, as C++ does not have genuine runtime reflection capabilities.
Upvotes: 1
Reputation: 146988
No, it cannot be. C++ does not support this kind of introspection. __PRETTY_FUNCTION__
is all you're gonna get.
Upvotes: 1
Reputation: 3191
From your description it seems you migth have a design issue. Have you considered using the template method design patter? The idea is to have your base class implement the common functionality and through virtual functions implement the specifics in your derived classes.
Upvotes: 1