为什么 C++ 没有 const 构造函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6936124/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does C++ not have a const constructor?
提问by Catskul
(Edit: Heavy change because previous example was flawed, which may make some answers/comments seem odd)
(编辑:重大更改,因为之前的示例存在缺陷,这可能会使某些答案/评论看起来很奇怪)
This might be an overly contrived, but the following is legal because of lack of const constructor:
这可能过于人为,但由于缺少 const 构造函数,以下是合法的:
class Cheater
{
public:
Cheater(int avalue)
: cheaterPtr(this) //conceptually odd legality in const Cheater ctor
, value(avalue)
{}
Cheater& getCheaterPtr() const {return *cheaterPtr;}
int value;
private:
Cheater * cheaterPtr;
};
int main()
{
const Cheater cheater(7); //Initialize the value to 7
cheater.value = 4; //good, illegal
cheater.getCheaterPtr().value = 4; //oops, legal
return 0;
}
It seems like providing a const constructor a thing would be as easy technically as const methods, and be analogous to a const overload.
似乎提供 const 构造函数在技术上与 const 方法一样简单,并且类似于 const 重载。
Note: I'm not looking for 'Image( const Data & data ) const
' but rather 'const Image( const Data & data) const
'
注意:我不是在寻找“ Image( const Data & data ) const
”而是“ const Image( const Data & data) const
”
So:
所以:
- Why is the const constructor absent in C++?
- 为什么 C++ 中没有 const 构造函数?
Here's some related material for context:
以下是上下文的一些相关材料:
采纳答案by Nicol Bolas
It would not be a const method itself
它本身不会是一个 const 方法
If this constructor were not a const
method itself, then the internal pointers and such would also not be const
. Therefore, it could not set const
values into those non-const
members.
如果此构造函数const
本身不是方法,则内部指针等也不会是const
. 因此,它无法const
为那些非const
成员设置值。
The only way to make it work syntactically is for this constructor to require member initialization for all non-mutable
members. Essentially, any member not declared mutable
would be implicitly declared const
when using this constructor. Which is equivalent to making the constructor a const
method; only initializers could initialize members. The constructor's body could do nothing with non-mutable members, because those members would be const
at that point.
让它在语法上工作的唯一方法是让这个构造函数要求所有非mutable
成员的成员初始化。本质上,任何未声明的成员mutable
都将const
在使用此构造函数时隐式声明。这相当于使构造函数成为const
方法;只有初始化器可以初始化成员。构造函数的主体不能对非可变成员做任何事情,因为那些成员将const
在那个点上。
What you are asking for is syntactically dubious. You're essentially trying to hoodwink the API, storing constant data in an object that is designed for mutable data (which is why you didn't declare the member pointer to be const
). If you want different behavior for an object, you need to declare the object to have that specific behavior.
你所要求的在语法上是可疑的。您实际上是在试图欺骗 API,将常量数据存储在为可变数据设计的对象中(这就是您没有将成员指针声明为 的原因const
)。如果您希望对象具有不同的行为,则需要声明该对象以具有该特定行为。
回答by Mark B
Just because Image
is const
in your imaginary constructor doesn't mean that what m_data
points to is. You'd end up being able to assign a "pointer to const" to a "const pointer to non-const" inside your class, which would remove constness without a cast. This would obviously allow you to violate invariants and couldn't be allowed.
正因为Image
是const
在你想象的构造并不意味着什么m_data
点是。你最终能够在你的类中将一个“指向常量的指针”分配给一个“指向非常量的常量指针”,这将在没有强制转换的情况下删除常量。这显然会允许您违反不变量并且是不允许的。
As far as I know, any specific sets of const-ness that are needed can be accurately and completely specified within the current standard.
据我所知,任何需要的特定常量集都可以在当前标准中准确而完整地指定。
Another way to look at it is that const
means the method doesn't mutate your object's state. A constructor's sole purpose is to initialize an object's state to be valid (well hopefully anyway - any constructors with side effects should be ...carefully evaluated).
另一种看待它的方式是这const
意味着该方法不会改变您对象的状态。构造函数的唯一目的是将对象的状态初始化为有效(希望无论如何 - 任何具有副作用的构造函数都应该......仔细评估)。
EDIT: In C++ constness applies to both members, and for pointers and references, to the accessible constness of the referred object. C++ consciously made the decision to split out these two different const-nesses. Firstly, do we agree that this code demonstrating the difference should compile and print out "non-const"?
编辑:在 C++ 中,常量适用于两个成员,对于指针和引用,适用于被引用对象的可访问常量。C++ 有意识地决定拆分这两种不同的常量。首先,我们是否同意这段演示差异的代码应该编译并打印出“非常量”?
#include <iostream>
struct Data
{
void non_const() { std::cout << "non-const" << std::endl; }
};
struct Image
{
Image( Data & data ) : m_data( data ) {}
void check() const { m_data.non_const(); }
Data & m_data;
};
int main()
{
Data data;
const Image img(data);
img.check();
return 0;
}
So then in order to obtain the behavior where it could accept a const-ref and store it as const-ref, the effective declaration of the reference would have to change to be const. This would then mean that it would be a completely distinct type, NOT a const
version of the original type (since two types with members differing in const-qualification are treated as two separate types in C++). Thus, either the compiler has to be able to do excessive behind-the-scenes magic to convert these things back and forth, remembering the const-ness of the members, or it has to treat it as a separate type which then couldn't be used in place of the normal type.
因此,为了获得可以接受 const-ref 并将其存储为 const-ref 的行为,引用的有效声明必须更改为 const。这将意味着它将是一个完全不同的类型,而不是const
原始类型的版本(因为成员在 const 限定上不同的两种类型在 C++ 中被视为两种单独的类型)。因此,要么编译器必须能够做过多的幕后魔法来来回转换这些东西,记住成员的常量性,要么它必须将它视为一个单独的类型,然后不能代替普通类型使用。
I think what you're trying to achieve is a referencee_const object, a concept that only exists in C++ as a separate class (which I suspect could be implemented with judicious use of templates although I didn't make an attempt).
我认为你想要实现的是一个 referencee_const 对象,这个概念只存在于 C++ 中作为一个单独的类(我怀疑可以通过明智地使用模板来实现,尽管我没有尝试)。
Is this strictly a theoretical question (answer: C++ decided to split object and referencee constness) or is there an actual practical uncontrived problem you're trying to solve?
这是一个严格的理论问题(答案:C++ 决定拆分对象和引用常量)还是您正在尝试解决一个实际的实际问题?
回答by bdonlan
Mark B goes over the fundamental considerations, but note that you can do something similar in pure C++. Consider:
Mark B 回顾了基本的考虑因素,但请注意,您可以在纯 C++ 中做类似的事情。考虑:
struct Data { };
class ConstImage {
protected:
const Data *const_data;
public:
ConstImage (const Data *cd) : const_data(cd) { }
int getFoo() const { return const_data->getFoo(); }
};
class Image : public ConstImage {
protected:
Data *data() { return const_cast<Data *>(const_data); }
public:
Image(Data *d) : const_data(d) { }
void frob() { data()->frob(); }
};
Instead of using const Image *
, use ConstImage *
, and there you go. You could also simply define a static function pseudo-constructor:
而不是使用const Image *
,使用ConstImage *
,然后就可以了。您也可以简单地定义一个静态函数伪构造函数:
const Image *Image::newConstImage(const Data *d) {
return new Image(const_cast<Data*>(d));
}
This, of course, relies on the programmer to ensure that there aren't any const
functions which might somehow mutate the pointed-to Data
's state.
当然,这依赖于程序员来确保没有任何const
函数可能以某种方式改变指向Data
的状态。
You can also combine these techniques:
您还可以结合使用这些技术:
class Image {
protected:
const Data *const_data;
Data *data() { return const_cast<Data *>(const_data); }
public:
void frob() { data()->frob(); }
int getFoo() const { return const_data->getFoo(); }
Image(Data *d) : const_data(d) { }
static const Image *newConst(const Data *cd) {
return new Image(const_cast<Data *>(cd));
}
};
This gets the best of both worlds; since data()
is a non-const member, you have static checking for mutation of the pointed-to value. You also, however, have a const constructor, and can directly cast between Image *
and const Image *
(ie, you can remove the constness if you know it is safe).
这是两全其美的;由于data()
是非常量成员,因此您可以静态检查指向值的突变。但是,您也有一个 const 构造函数,并且可以直接在Image *
and之间进行转换const Image *
(即,如果您知道它是安全的,您可以删除它)。
You can also abstract away the separation of pointers further:
您还可以进一步抽象出指针的分离:
template<typename T>
class ConstPropPointer {
private:
T *ptr;
public:
ConstPropPointer(T *ptr_) : ptr(ptr_) { }
T &operator*() { return *ptr; }
const T &operator*() const { return *ptr; }
T *operator->() { return ptr; }
const T *operator->() const { return ptr; }
};
class Image {
protected:
ConstPropPointer<Data> data;
public:
void frob() { data->frob(); }
int getFoo() const { return data->getFoo(); }
Image(Data *d) : data(d) { }
static const Image *newConst(const Data *cd) {
return new Image(const_cast<Data *>(cd));
}
};
Now, if this
is const, data
becomes const, propagating that into *data
as well. Good enough for you? :)
现在,如果this
是 const,data
变成 const,也将其传播到*data
。对你来说足够好吗?:)
I suppose the final answer is probably this: In order for a const constructor to be useful and safe, we'd need something like the ConstPropPointer
you see there built into the language. Const constructors would then be allowed to assign from const T *
to constprop T *
. This is more complex than it sounds - for example, how does this interact with template classes such as vector
?
我想最终的答案可能是这样的:为了使 const 构造函数有用且安全,我们需要像ConstPropPointer
您在语言中看到的那样的东西。然后将允许 const 构造函数从const T *
to赋值constprop T *
。这比听起来更复杂 - 例如,它如何与模板类交互,例如vector
?
So, this is a somewhat complex change, but the problem doesn't seem to come up all that much. More importantly, there's a simple workaround here (the ConstPropPointer
can be librarized, and the static pseudo-constructor is simple enough to add). So the C++ committee probably passed it over for more important things, if it was even proposed at all.
所以,这是一个有点复杂的变化,但问题似乎并没有那么多。更重要的是,这里有一个简单的解决方法(ConstPropPointer
可以被库化,并且静态伪构造函数很容易添加)。因此,C++ 委员会可能会将它用于更重要的事情,如果它甚至被提出的话。
回答by Mel Viso Martinez
In my opinion, the fact of that the ctors haven't return-type specification is what fails here. Any other imaginable syntax like for example
在我看来,ctors 没有返回类型规范的事实是这里失败的原因。任何其他可以想象的语法,例如
class A
{
const A& ctor(...);
}
would be, imho, very valuable. For example, imagine such a situation of calling a method with prototype
将是,恕我直言,非常有价值。例如,想象这样一种使用原型调用方法的情况
void my_method(const my_own_string_class& z);
If my_own_string_class holds a ctor from char*, the compiler could choose this ctor, but as this ctor is not allowed to return a const object, it need to allocate and copy... If const return type were allowed, one could do
如果 my_own_string_class 持有一个来自 char* 的 ctor,编译器可以选择这个 ctor,但是由于这个 ctor 不允许返回一个 const 对象,它需要分配和复制......如果允许 const 返回类型,可以这样做
class my_own_string_class
{
char *_ptr;
public:
const my_own_string_class& ctor(char *txt)
: _ptr(txt)
{ return *this;}
}
provided that this special construct be restricted to the creation of temporal instances. (And dtor's must be mutable ;) ).
前提是此特殊构造仅限于创建时间实例。(并且 dtor 必须是可变的 ;) )。
回答by aevanko
Const objects should initialize their member variables and a const constructor wouldn't be able to do so.
const 对象应该初始化它们的成员变量,而 const 构造函数则不能这样做。