强制类实例为const

时间:2017-01-22 16:11:17

标签: c++

有没有办法强制只允许实例化类的const实例,并且编译器会将非const实例检测为错误?

3 个答案:

答案 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;
}