有没有办法强制只允许实例化类的const实例,并且编译器会将非const实例检测为错误?
答案 0 :(得分:6)
是否存在采用现有类的通用方法,并通过删除所有非const功能来“理解”它?
一种可能的解决方法是创建一个包含类的实例的包装类,并且只允许访问const
对它的引用。
template<class T>
class Immutable {
public:
template<typename... Args>
Immutable(Args&&... args) : instance(forward<Args>(args)...) {
}
operator const T&() {
return instance;
}
const T& get() const {
return instance;
}
private:
Immutable& operator=(const Immutable& other) = delete;
T instance;
};
假设您有一个可变类Class
:
class Class {
public:
Class() : m_value(0) {
}
Class(const Class& other) : m_value(other.m_value) {
}
Class(int value) : m_value(value) {
}
Class(int x, int y) : m_value(x + y) {
}
void change(int value) {
m_value = value;
}
int value() const {
return m_value;
}
private:
int m_value;
};
以下是Immutable<Class>
的使用方法:
void functionTakingConstReference(const Class& x) {
}
void functionTakingNonConstReference(Class& x) {
}
void functionTakingImmutableClass(Immutable<Class>& x) {
}
void functionTakingValue(Class x) {
}
int main(int argc, char *argv[])
{
// Any constructor of Class can also be used with Immutable<Class>.
Immutable<Class> a;
Immutable<Class> b(1);
Immutable<Class> c(2, 3);
Immutable<Class> d(c);
// Compiles and works as expected.
functionTakingConstReference(a);
functionTakingImmutableClass(a);
functionTakingValue(a);
cout << a.get().value() << endl;
// Doesn't compile because operator= is deleted.
// b = a;
// Doesn't compile because "change" is a non-const method.
// a.get().change(4);
// Doesn't compile because the function takes a non-const reference to Class as an argument.
// functionTakingNonConstReference(a);
return 0;
}
答案 1 :(得分:1)
有没有办法强制只允许实例化类的const实例,并且编译器会将非const实例检测为错误?
没有
但是你可以将所有成员声明为const。然后const和非const实例的行为大致相同,并且实例是否为const无关紧要。
答案 2 :(得分:1)
我认为你正在寻找一个不可变的类。获得不变性的简单方法是将所有成员变量声明为const
。这样,您可以确保在构造后对象的状态不会发生变化。
此保证与您的对象是否为const
无关,即使您具有该类的non-const
成员函数。
例如:
class Foo
{
public:
Foo(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
private:
const int m_id;
const double m_value;
};
您可以通过模板类生成任何类型的不可变对象的另一种方法。像这样:
class Bar
{
public:
Bar(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
void SetId(int id) { m_id = id; }
private:
int m_id;
double m_value;
};
template<typename T>
class MyImmutable
{
public:
const T m_obj;
MyImmutable(const T& obj) : m_obj(obj)
{ }
};
int main()
{
cout << "Hello World!" << endl;
Foo a(1,2.0);
Bar x(2,3.0);
MyImmutable<Bar> y(x);
cout << "a.id = " << a.Id() << endl;
cout << "a.value = " << a.Value() << endl;
cout << "y.id = " << y.m_obj.Id() << endl;
cout << "y.value = " << y.m_obj.Value() << endl;
y.m_obj.SetId(2); // calling non-const member throws an error.
return 0;
}