2016-01-27 4 views
1

У меня есть базовый класс Base, со многими производными классами (например, Derived1, Derived2). Base имеет чистую виртуальную функцию fn, которая называется многократно с помощью указателя Base. Каждый раз, когда вызывается функция, мне нужно сделать некоторые дополнительные записи и связанные с ними вещи. В частности, я использую 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(); 
} 
+4

Можете ли вы опубликовать небольшой пример того, чего вы хотите достичь, поэтому мы не отвечаем на «неправильные» вопросы? –

+1

(Я уверен, из описания 'BOOST_CURRENT_FUNCTION', что это просто оболочка для' __PRETTY_FUNCTION__' или что-то подобное) –

+2

Сделать метод не виртуальным, позволить ему вести книгу и вызывать действительную виртуальную функцию, methodImpl , – erenon

ответ

1

Нет, этого не может быть. C++ не поддерживает такую ​​интроспекцию. __PRETTY_FUNCTION__ это все, что ты собираешься получить.

+0

Я думаю, что вы правда, но надеясь увидеть какой-то чудесный подход. – SPMP

1

Из вашего описания, похоже, у вас есть проблема с дизайном. Считаете ли вы использование template method design patter? Идея состоит в том, чтобы ваш базовый класс реализовал общую функциональность и через виртуальные функции реализовал специфику в ваших производных классах.

+0

Проблема в том, что это не обычная функциональность? Функциональность, которую я хочу, - это увидеть, какая вызываемая функция вызывается. – SPMP

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++ не обладает подлинными возможностями отображения времени выполнения.

+0

Я бы не назвал это шаблоном проектирования шаблона чистого шаблона. Но в конце концов это всего лишь семантика. На мой взгляд, метод шаблона будет иметь Base :: f() не быть чистой виртуальной функцией, а обычной функцией, которая, в свою очередь, вызывает частный виртуальный метод, который затем реализуется в производных классах. Но, как я сказал, что все будет сделано :) – LordDoskias

+0

@LordDoskias Да, я считаю, что это вопрос семантики. Я знал об этом из «Эффективного C++» Скотта Майерса, в котором упомянул тот факт, что общий бухгалтерский учет может быть достигнут путем реализации чистой виртуальной функции (которая в то время я понятия не имел, что можно сделать). – vsoftco

+0

um .. Идея состоит в том, чтобы иметь бухгалтерский код только один раз (это не просто печать имени функции). Этот подход не помогает, верно? – SPMP

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, или некоторые такие, и все еще хотят, чтобы он работал корректно, когда он «ничего»)

0

Самый простой ответ заключается в том, что поскольку C++ не имеет вспомогательных методов, вам необходимо разделить реализацию fn на утилита-обертка d виртуальная функция собственно:

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; 

в начале функции.