繁体   English   中英

为什么C ++没有const构造函数?

[英]Why does C++ not have a 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;
}

看起来,提供const构造函数在技术上和const方法一样容易,并且类似于const重载。

注意:我不是在寻找' Image( const Data & data ) const '而是' const Image( const Data & data) const '

所以:

  • 为什么C ++中没有const构造函数?

以下是一些有关上下文的材料:

仅仅因为Image在您虚构的构造const中为const ,并不意味着m_data指向的是。 您最终将能够在类内部将“指向const的指针”分配给“指向非const的const指针”,这将删除constness而无需强制转换。 显然,这将允许您违反不变式,并且不允许这样做。

据我所知,可以在当前标准中准确,完整地指定所需的任何特定的常数集。

另一种看待它的方式是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;
}

因此,为了获得可以接受const-ref并将其存储为const-ref的行为,必须将引用的有效声明更改为const。 然后,这将意味着它将是一个完全不同的类型,而不是原始类型的const版本(因为在const中,成员类型不同的两种类型在C ++中被视为两种单独的类型)。 因此,编译器要么必须能够做大量的幕后魔术来来回转换这些东西,记住成员的常数,要么就必须将其视为一个单独的类型,而后又不能代替普通类型使用。

我认为您想要实现的是referencee_const对象,该概念仅在C ++中作为单独的类存在(我怀疑可以通过谨慎使用模板来实现,尽管我没有尝试过)。

严格来说,这是理论上的问题吗(答案:C ++决定拆分对象和引用常量),或者您要解决的是实际的实际人为问题?

它本身不是const方法

如果此构造方法本身不是const方法,则内部指针等也将不是const 因此,它无法将const值设置为这些非const成员。

进行的唯一方式,语法,工作是这个构造要求成员初始化所有非mutable成员。 本质上,使用此构造const时,任何未声明为mutable成员都将隐式声明为const 这相当于使构造函数成为const方法; 只有初始化程序才能初始化成员。 构造函数的主体不能对非可变成员执行任何操作,因为在那一点上那些成员将是const

您要的是语法上可疑的。 本质上,您试图欺骗API,将常量数据存储在旨在用于可变数据的对象中(这就是为什么未将成员指针声明为const )。 如果您希望对象具有不同的行为,则需要声明该对象具有该特定行为。

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(); }
};

而不是使用const Image * ,而是使用ConstImage * ,然后就可以了。 您还可以简单地定义一个静态函数伪构造函数:

const Image *Image::newConstImage(const Data *d) {
  return new Image(const_cast<Data*>(d));
}

当然,这依赖于程序员来确保不存在任何可能以某种方式使指向Data的状态发生变化的const函数。

您还可以结合使用以下技术:

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));
  }
};

这是两全其美的。 由于data()是非常量成员,因此您需要对指向的值进行静态检查。 但是,您也具有const构造函数,并且可以直接在Image *const Image * (即,如果知道安全性,则可以删除const Image * )。

您还可以进一步抽象指针的分离:

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));
  }
};

现在,如果this是const,则data变为const,并将其也传播为*data 对你足够好吗? :)

我想最终的答案可能是这样的:为了使const构造函数有用且安全,我们需要在语言中内置类似ConstPropPointer类的东西。 然后,将允许const构造函数将const T *分配给constprop T * 这比听起来要复杂得多,例如,这如何与模板类(例如vector相互作用?

因此,这是一个有点复杂的更改,但是问题似乎并没有解决的那么多。 更重要的是,这里有一个简单的解决方法( ConstPropPointer可以被解放,而静态伪构造函数很容易添加)。 因此,C ++委员会可能甚至将其移交给更重要的事情,甚至根本没有提出。

在我看来,ctor没有返回类型说明这一事实在这里是失败的。 任何其他可以想象的语法,例如

class A
{
    const A& ctor(...);
}

恕我直言,这将是非常有价值的。 例如,想象一下用原型调用方法的情况

void my_method(const my_own_string_class& z);

如果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;}
 }

前提是该特殊构造仅限于时间实例的创建。 (并且dtor必须是可变的;))。

const对象应该初始化其成员变量,而const构造函数将无法这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM