Неясно, чего вы пытаетесь достичь. Но вас уже спрашивали об этом, и вы не смогли многое прояснить. В своем ответном комментарии вы написали: «Я имею в виду не только [запретить] создание экземпляров, но и любые ссылки на класс (например, использование его в качестве типа параметра в функции)».
Взятый по номиналу, это означает использование в заголовочном файле следующего:
struct BlahImpl;
typedef boost::shared_ptr<BlahImpl> Blah;
// Functions that create or give access to Blah instances.
Клиентский код может затем создавать или получать доступ к Blah
экземплярам и копировать их (с подразумеваемой общей семантикой), но фактически ничего с ними не делать. В лучшем случае они могут служить доказательством того, что некоторая функция была вызвана ранее (производя экземпляр). Или, возможно, что-то контролируется шаблоном вызовов функций, включающих такие экземпляры, но в любом случае boost::shared_ptr
будет тогда совершенно неактуальным и излишним.
Так что, возможно, вы имели в виду не совсем то, что написали, а что-то вроде «Любой BlahImpl
экземпляр должен быть динамически выделен и инкапсулирован boost::shared_ptr
».
И если это так, вы можете достичь этого следующим образом:
Вы можете принудительно применить динамическое распределение, сделав деструктор не public
, предпочтительно protected
, и предоставив некоторые средства для уничтожения экземпляров (самое простое, чтобы присвоить friend
-ship на общем шаблоне функции уничтожения). ).
Вы можете обеспечить обертывание заданной интеллектуальной точкой несколькими способами. Основная проблема заключается в пересылке аргументов конструктора. Один из совместимых с C ++ 98 способов состоит в том, чтобы выполнить эту пересылку с помощью макроса, и в этом случае «вы не можете случайно создать экземпляры, отличные от этого макроса», может быть реализовано с помощью обфускации , а именно обфускации new
выражение.
Пример:
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <stddef.h> // ptrdiff_t, size_t
#include <string>
using namespace std;
namespace cpp11 {
using boost::shared_ptr;
};
template< class Type >
void destroy( Type const* p ) { delete p; }
class OnlySharedPtrUsage
{
public:
virtual ~OnlySharedPtrUsage() {}
struct InstantiationObfuscation;
static void* operator new( size_t size, InstantiationObfuscation* )
{
return ::operator new( size );
}
static void operator delete( void* p, InstantiationObfuscation* )
{
::operator delete( p );
}
static void operator delete( void* p )
{
::operator delete( p );
}
};
#define NEW_SHARED( type, args ) \
::cpp11::shared_ptr<type>( \
new( (type::InstantiationObfuscation*)0 ) type args, \
destroy<type> \
)
class MyClass
: public OnlySharedPtrUsage // The NEW_SHARED macro simplies.
{
template< class Type > friend void destroy( Type const* );
private:
string helloText_;
MyClass( MyClass const& ); // No such.
MyClass& operator=( MyClass const& ); // No such.
protected:
virtual ~MyClass() // Only dynamic allocation allowed.
{
cout << "MyClass::<destroy>()" << endl;
}
public:
string helloText() const { return helloText_; }
MyClass( string const& text )
: helloText_( text )
{
cout << "MyClass::<init>( string )" << endl;
}
};
int main()
{
// MyClass o( "a" ); // ! Does not compile, not dynamic.
// MyClass* p = new MyClass( "b" ); // ! Does not compile, not "mangled".
cpp11::shared_ptr< MyClass > sp = NEW_SHARED( MyClass,( "Hello from MyClass!" ) );
cout << sp->helloText() << endl;
}
Обратите внимание, что этот пример напрямую не поддерживает оптимизацию make_shared
. Запутанная функция выделения (формально функция размещения) не совсем подходит для make_shared
. Но я представляю, что это можно сделать, определив класс распределителя и используя alloc_shared
.
Также обратите внимание, что этот подход поддерживает только модули заголовков; нет необходимости в отдельной компиляции. : -)
Да, и для общего случая вам также необходимо добавить функции-распределители для массивов.
Приветствия & hth.,