Настраиваемая виртуальная функция

#c #polymorphism

#c #полиморфизм

Вопрос:

Я должен разработать библиотеку с использованием C , и ниже приведены мои требования.

  1. Пользователи должны иметь возможность расширять методы моего класса API
  2. Виртуальные методы, реализованные пользователем, будут вызываться внутри библиотеки полиморфно
  3. Я должен помещать две записи журнала до и после каждого вызова виртуального метода
  4. Когда пользователь создает свои собственные классы и виртуальные методы, И если он / она использует мою библиотеку (имеет ссылку на), в дополнение к обычной динамической привязке, вышеуказанный пункт 3 (имеющий две записи журнала) должен быть удовлетворен

Идея может быть изложена в общих чертах следующим образом?

 class BaseClass
{
public:
    virtual void foo() = 0;
};
  

Пользовательская реализация была бы похожа

 class DerivedClass: public BaseClass
{
public:
    virtual void foo() {/*come impl*/}
};
  

Используя следующий код,

 BaseClass * bp = new DerivedClass();
bp->foo();
  

Должно быть эквивалентно чему-то вроде,

 BaseClass * bp = new DerivedClass();
log_start(typeid(*bp).name());
bp->foo();
log_end(typeid(*bp).name());
  

Но я не могу попросить пользователей моей библиотеки (и даже я не могу делать это везде) размещать эти материалы для ведения журнала всякий раз, когда они используют мой API. Поскольку существует множество виртуальных функций и их использование, я не могу поместить ведение журнала везде в моей библиотеке.

Есть ли какой-нибудь простой способ добиться этого? Нужно ли мне создавать свою собственную виртуальную таблицу?

Ответ №1:

Вместо того, чтобы вызывать их foo напрямую, вы могли бы использовать пользовательскую реализацию foo , но вместо этого вызывать bar . bar завершил бы вызов на foo , как в:

 class BaseClass { 
public:
    void bar() {
        log_start(typeid(*this).name());
        foo();
        log_end(typeid(*this).name());
    }

protected:
    virtual void foo() = 0;
};
  

Использование было бы:

 BaseClass * bp = new DerivedClass();
bp->bar();
  

Ответ №2:

Для этого случая вам следует использовать что-то вроде шаблона Template Method шаблон

 class BaseClass
{
public:
    void foo() {
         log_start(typeid(*this).name()); 
         doFoo(); 
         log_end(typeid(*this).name()); 
    }
protected:
    virtual void doFoo() = 0;
};
  

 class DerivedClass: public BaseClass
{
protected: // or private, depends on use case
    virtual void doFoo() {/* some impl */}
};
  

 int main() {
    BaseClass * bp = new DerivedClass();
    bp->foo();
    delete bp;
    return 0;
}
  

Смотрите рабочий пример здесь.

Комментарии:

1. Спасибо, хорошая техника