1

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

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

然后是一个具体的:

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

5 回答 5

5

您的第一段详细说明了 C++ 如何灵活并允许您表达许多不同的程序。

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

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

于 2012-11-28T13:32:02.937 回答
4

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

想到的第一个问题是,当拥有一个所有对象都适用的类型const是一件自然的事情时。有些类型是自然不可变的,在某些语言中甚至建议使尽可能多的类型不可变,但这与强制所有对象都是不可变的不是一回事const

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

既然高层次的效果可以通过不同的方式以很少的成本实现,你为什么要让一门复杂的语言变得更加复杂而没有附加价值呢?

虽然上面的问题似乎是夸夸其谈,但事实并非如此。考虑扩展语言的标准之一是投资回报:如果没有它,我们将能够用这个功能做什么?(即这是一个启用特性吗?)如果答案是什么,那么下一个问题是与当前状态相比,使用此特性的程序员的生活会简单多少?(对于非启用功能,添加它们有什么价值?)

启用类别中,示例将是rvalue-references;如果没有该语言功能,您将无法实现完美转发,也无法实现移动语义。在第二类中,您可以考虑 lambdas——没有它们就无法使用 lambdas 做任何事情——它的价值在于简化用户代码(必须进行复杂的代码:创建一个仿函数,声明正确的类型,提供一个构造函数来初始化——执行捕获——成员......)但是使用 lambdas 代码变得更加简单。请注意,Sutter 花了很多时间来说服 Stroustrup lambda 具有价值。

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

于 2012-11-28T14:50:17.887 回答
2

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

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

于 2012-11-28T13:41:16.063 回答
0

只需将您的类实例创建为const. 这将确保所有内部结构都是const.

例如const MY_TYPE obj;

于 2012-11-28T13:29:44.583 回答
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.也会有所帮助。

当然,更便宜的替代方法是在名称中给出类const的名称,struct A_const{...或者struct cA{...暗示这才const有意义。(也许,如果你决定以后有变异的成员,你可以从这里继承,struct A : A_const{...)。

于 2017-09-06T08:45:13.720 回答