I need to ban the user from calling the class T
's regular constructors as follows:
T obj (a, b, c); // Compile-time error
T* objPtr = new T (a, b, c); // OK
Is it possible in C++?
I need to ban the user from calling the class T
's regular constructors as follows:
T obj (a, b, c); // Compile-time error
T* objPtr = new T (a, b, c); // OK
Is it possible in C++?
You can mimic that behaviour kinda by using a factory pattern: a friend class
used to instantiate instances of an object:
class T;
class TMaker
{
public:
static std::unique_ptr<T> MakeT(int a, int b, int c);
};
class T
{
public:
void PrintMe() { std::cout << a << ", " << b << ", " << c << std::endl; }
private:
T(int a_, int b_, int c_) : a(a_), b(b_), c(c_) {}
int a, b, c;
friend class TMaker;
};
std::unique_ptr<T> TMaker::MakeT(int a, int b, int c)
{
return std::unique_ptr<T>{new T{a, b, c}};
}
Now users can no longer construct your class directly:
T v { 1, 2, 3 }; // doesn't work
T* v = new T{1, 2, 3}; // also doesn't work
And instead they can only use the following:
std::unique_ptr<T> t = TMaker::MakeT(1, 2, 3);
However, be aware that you may just have an XY problem.
Like Tas pointed out, you need to use a factory. But I think a simple factory function in the class itself is enough.
#include <iostream>
#include <memory>
template <class C>
struct creator
{
template<typename... Args>
static std::unique_ptr<C> create(Args&&... args)
{ return std::unique_ptr<C>( new C(std::forward<Args>(args)...) ); }
};
class MyClass : public creator<MyClass>
{
private:
friend class creator<MyClass>;
MyClass(int) { std::cout << "Created"; }
};
int main()
{
auto p = MyClass::create(0);
return 0;
}
Since you most probably don't want to repeat yourself, you can create a helpful little templated Mixin (like I did above). This will save you the work of typing the same boilerplate code for every class like this that you make. An added benefit is that using the template will provide a consistent interface and naming convention across all classes in your application, that need to behave the same way.
And consistency is good in software, as we all know.
Make destructor private, and provide a delete function. That would make both of your statements work.
class T
{
public:
void PrintMe();
T(int a_, int b_, int c_);
void deleteMe() { delete this;}
private:
~T(){}
int a, b, c;
};