Доступ к указателю "this" конкретного класса из интерфейса

После написания теста я определил, что this указатель в интерфейсе не равен this указатель на конкретный класс, что означает, что я не могу просто использовать приведение в стиле C

class AbstractBase {...};

class AnInterface {
public:
    AnInterface() {...} // need AbstractBase * here 
    ~virtual AnInterface() {...} // and here
};

class Concrete : public AbstractBase, public AnInterface {};

Моему интерфейсу нужен указатель базового класса на конкретный класс, наследующий его в конструкторе и деструкторе для обработки регистрации и отмены регистрации, связанной с интерфейсом.

Каждый конкретный объект, который наследует интерфейс, должен сначала наследовать абстрактный базовый класс, он всегда первый в макете.

Для конструктора это не так уж сложно, я могу добавить указатель в конструктор интерфейса и передать this из конкретного класса. Но у деструктора нет никаких параметров, поэтому я там в неведении.

Решения, которые я придумала, идут с накладными расходами:

1 - сохранить указатель в интерфейсе, который будет использоваться в деструкторе - добавляет в один указатель затраты памяти

class AnInterface {
public:
    AnInterface(AbstractBase * ap) {...}
    ~virtual AnInterface() {...} // and here
private:
    AbstractBase * aPtr;
};

...
Concrete() : AnInterface(this) {}

2 - создать абстрактный интерфейс в интерфейсе и реализовать его для возврата this в конкретном классе - добавляет накладные расходы для виртуального вызова

class AnInterface {
    virtual AbstractBase * getPtr() = 0;
};

class Concrete : public AbstractBase, public AnInterface {
    AbstractBase * getPtr() { return this; }
};

3 - dynamic_cast еще хуже

Есть ли более эффективный способ добиться этого?

3 ответа

Решение

IMO, если разъединение между базовым классом и интерфейсом действительно необходимо, оба решения 1 и 2 имеют допустимые накладные расходы, что, разумеется, не будет проблемой для современного оборудования.

Но поскольку вы говорите, что интерфейс предназначен для работы с функциональными возможностями, представленными в базовом классе, то, возможно, развязка не очень хорошая вещь.

Я имею в виду, если проблема заключается в наследовании нескольких интерфейсов, которые все наследуют базовый класс, или в проблеме "страшного бриллианта" с наследованием, вы можете просто использовать виртуальное наследование.

Все ваши проблемы кажутся микрооптимизациями. Предполагая, что вы действительно не можете отделить свой интерфейс от своей реализации (в таком случае, почему вы используете интерфейсы в первую очередь?), Я бы просто использовал dynamic_cast и покончим с этим, хотя он довольно тяжелый. Если бы я застрял на платформе, где RTTI не вариант, я бы использовал вариант 2.

У вашего дизайна есть некоторые недостатки.

Вы должны рассмотреть возможность использования CRTP с точки зрения Mixin, что избавляет вас от необходимости держать дополнительный указатель на конкретный производный.

template<typename Derived>
class AnInterface {
public:
    AnInterface() {
       Derived* derived = static_cast<Derived*>(this);
       AbstractBase* abstractBase = static_cast<AbstractBase*>(derived);
    } // have AbstractBase * here 
    ~virtual AnInterface() {...} // and here
};

class Concrete 
: public virtual AbstractBase
, public AnInterface<Concrete> {
    AbstractBase * getPtr() { return this; }
};
Другие вопросы по тегам