要求const对象的C ++类

时间:2012-11-28 13:28:25

标签: c++

首先让我问一个普遍的问题:

  • 在我看来,C ++是一种语言,它的目的是提供大量的功能,为程序员提供最大的灵活性,以他认为合适的方式做事。换句话说,它是一种灵活的语言,允许程序员以比我见过的任何其他语言更多的方式表达自己。这是对的吗?

然后是特定的一个:

  • 为什么C ++似乎不支持创建对象只能const的类?换句话说,如果您尝试创建非const对象,则会遇到编译时错误的类。在许多情况下,这似乎是很自然的事情,但C ++不允许这样做。 这背后的原因是什么? (当然,我可以让所有成员const,但这有点像拼写。)

5 个答案:

答案 0 :(得分:5)

您的第一段详细介绍了C ++的灵活性,并允许您表达许多不同的程序。

你的第二段询问为什么C ++不允许程序员强制执行一个具有可疑益处的严格限制(当你可以简单地标记所有成员const以获得几乎相同的结果时)。

让我们每个人从这种二分法中得出自己的结论。 :)

答案 1 :(得分:4)

  

为什么C ++似乎不支持创建对象只能是const的类?换句话说,如果您尝试创建它的非const对象,则会遇到编译时错误的类。在许多情况下,这似乎是很自然的事情,但C ++不允许这样做。这背后的原因是什么?

首先想到的问题是,拥有一个所有对象都是const的类型是很自然的事情。有些类型是自然不可变的,在某些语言中,甚至建议尽可能多地使不可变类型,但这与强制所有对象都是const不同。 / p>

在类设计中,控制是否有任何成员函数修改实现不可变对象的对象的状态是微不足道的。然后封装会发挥作用,如果你没有公开任何变异函数,那么类型是不可变const一样好。您还可以(如果您需要额外的安全性)将所有成员数据限定为const,让编译器告诉您是否在自己的代码中违反了自己的约束。请注意,隐式强制所有对象const会将所有成员数据标记为const,而非常量函数无用

鉴于高水平的效果可以通过不同的方式以较低的成本实现,为什么你会使复杂的语言变得更加复杂而没有附加价值呢?

虽然上面的问题可能看起来很夸张,但事实并非如此。考虑扩展该语言的标准之一是投资回报率:如果没有它,我们能够使用此功能做什么? (即这是一个启用功能吗?)如果答案是什么,那么接下来的问题是程序员与当前状态相比这个功能的生命有多简单? (对于非启用功能,添加它们的价值是什么?)

启用类别中,示例将是 rvalue-references ;如果没有该语言功能,则无法实现 perfect-forwarding ,也无法实现 move-semantics 。在第二类中你可以考虑lambdas - 没有任何东西可以用lambdas完成,没有它们是不可行的 - 它的价值在于简化用户代码(必须复杂的代码:创建一个仿函数,声明所有成员的正确的类型,提供一个初始化的构造函数 - 捕获 - 成员...)但使用lambdas代码变得更加简单。请注意,Sutter花了很多时间来说服Stroustrup说lambdas有价值。

在您的情况下,您要求的不是启用功能,并且支持没有该功能的用例的成本足够低,以至于它不会将其作为核心语言功能提供。

答案 2 :(得分:2)

C ++语言设计的关键在于它以极少的(通常为零)成本提供抽象。使用类并不比在C中提供结构和相关函数更昂贵,但编译器可以对代码强制实施限制,以便实现类的语义优势。对于模板,引用,lambdas,复制/移动语义,字符串,I / O等也是如此。你不支付你不使用的东西,当你使用某些东西时,你付的很少。

C ++的另一个重要设计原则是它不提供不仅可以从其他语言特性轻松构建的语言特性,也不能为作者提供有用的抽象形式。每种语言功能都是一个构建块,可用于制作完全富有表现力的程序。这有助于灵活性。如果语言要提供您正在寻找的功能,那将会降低灵活性。如果您希望对象的状态为const,无论客户端如何使用它,您都需要使对象的每个成员const - 成员是您的对象的状态。 C ++不想给你绝对的一切;它只是为您提供必要的工具,以最低的成本编写完全富有表现力的代码。

答案 3 :(得分:0)

只需将您的班级实例创建为const即可。这将确保所有内部都是const

E.g。 const MY_TYPE obj;

答案 4 :(得分:0)

我曾经遇到过这种情况。 那是, 我设计了一个类,由于不可接受的性能要求,它基本上是不可变的。 不可变的,因为它的实例可以在构造中定义而且从不修改。 实际上,它的所有成员函数都是const。 (好吧,还有一个侧面问题,因为它是否可以分配,但让我们继续)。

能够强制使用声明实例const以使意图更明显是很好的。

我不认为C ++支持这一点而不添加间接级别,即通过const指针访问对象并禁用直接构造。 (或者甚至更好unique_ptr)。

struct A{ // this class is immutable, so in princple `A a` and `A const a` should behave the same
    int f() const{return 5;}
    private:
    A(){}
    public:
    template<class... Args>
    static A const* make_const(Args&&... args){return new A(std::forward<Args>(args)...);}
};

int main(){
    std::unique_ptr<A const> a(A::make_const());
    std::cout << a->f() << std::endl;
}

请注意,以下内容未按预期编译:

A a; // doesn't compile because the constructors are private

也不是

std::unique<A> a(A::make_const()); // make creates pointers to const, so this doesn't compile.

只有以下编译,并且有效地强制要求const

std::unique_ptr<A const> a(A::make());

可以使用std::indirect http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0201r1.pdf来改善它,并且将来重载operator.也会有所帮助。

当然,更便宜的替代方法是让类名conststruct A_const{...的名称为struct cA{...,以暗示只有const才有意义。 (也许,如果你以后决定让变异成员,你可以继承,struct A : A_const{...)。