Я начинаю использовать общие указатели в C ++ (Visual Studio 2010) и сталкиваюсь со следующей проблемой.
Я пишу новый модуль, который определяет интерфейс, который сообщает модулю, как вести себя в определенных условиях. Это что-то вроде этого (искусственный пример, чтобы проиллюстрировать мою проблему):
// Interface that should be implemented by user of the module
class RingAlert
{
public:
virtual void ring() = 0;
};
// Module that does something important
class Module
{
public:
Module (RingAlert &ringAlert) : m_ringAlert(ringAlert) {}
void dosomething(); // may call RingAlert::ring if something goes wrong.
private:
RingAlert &m_ringAlert;
};
Для облегчения работы пользователей модуля, а также потому, что RingAlert может передаваться и другим модулям, сейчас я делаю этот общий указатель, например:
typedef std::shared_ptr<RingAlert> RingAlertPtr;
class Module
{
public:
Module (RingAlertPtr ringAlert) : m_ringAlert(ringAlert) {}
void dosomething(); // may call RingAlert::ring if something goes wrong.
private:
RingAlertPtr m_ringAlert;
};
Теперь пользователи модуля могут создавать новый экземпляр RingAlert и просто передавать его модулю, не сохраняя его где-либо и не удаляя его в конце приложения.
Проблема начинается, если приложение делает что-то вроде этого:
class MyRingAlert : public RingAlert
{
public:
virtual void ring() {std::cout << "ring ring" << std::endl;}
};
class Application
{
public:
private:
MyRingAlert m_myRingAlert;
};
// later, somewhere in application code
Module m(RingAlertPtr(&m_myRingAlert));
В этом примере приложение берет адрес элемента данных и помещает его в общий указатель.
Позже в приложении деструктор модуля удалит общий указатель, который уменьшит счетчик ссылок и который затем удалит оповещение о вызове, которое не должно быть удалено, поскольку оно является элементом данных класса Application.
Я нашел способ предотвратить удаление экземпляра указателем с помощью этого (используя лямбда-выражения, но есть и более чистое решение с использованием функции):
Module m(RingAlertPtr(&m_myRingAlert,[](void *){});
Хотя это решает мою проблему, я не совсем доволен этим, потому что это все равно будет создавать проблему, если класс Application будет уничтожен до класса Module.
Единственное хорошее решение, похоже, состоит в том, чтобы заставить остальную часть приложения к новому экземпляру RingAlert (или фактически классу, который реализует RingAlert).
Можно ли это сделать?
Есть ли способ предотвратить создание экземпляров кода в подклассах базового класса в стеке или в качестве элемента данных?
Другими словами: можем ли мы заставить подклассы базового класса обновляться, если они хотят быть созданы?