Доступ к указателю "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; }
};