简体   繁体   English

用 const 成员替换某个类型的变量

[英]Replace a variable of a type with const members

Suppose I have a class with some constant member:假设我有一个带有一些常量成员的类:

class MyClass {
public:
   MyClass(int a) : a(a) {
   }
   MyClass() : MyClass(0) {
   }
   ~MyClass() {
   }
   const int a;
};

Now I want to store an instance of MyClass somewhere, eg as a global variable or as an attribute of another object.现在我想在某处存储MyClass的实例,例如作为全局变量或作为另一个对象的属性。

MyClass var;

Later, I want to assign a value to var :后来,我想给var赋值:

var = MyClass(5);

Obviously, this does not work, because the assign operator is invoked, which does not exist by default, because MyClass has a const attribute.显然,这行不通,因为调用了赋值运算符,默认情况下不存在,因为MyClass有一个 const 属性。 So far so good.到现在为止还挺好。

My question is, how can I assign a value to var anyway?我的问题是,无论如何我如何为var赋值? After all, var itself is not declared to be a constant.毕竟, var本身并没有被声明为常量。

My thoughts so far到目前为止我的想法

I know that the problem does not exist if I use a pointer for var :我知道如果我对var使用指针,则问题不存在:

MyClass *var;
var = new MyClass(5);

However, I would not like to use a pointer for convenience reasons.但是,出于方便的原因,我不想使用指针。

A potential solution is to overwrite the memory with placement new:一个潜在的解决方案是用placement new 覆盖内存:

template<class T, class... Args>
T &emplaceVar(T &myVar, Args&&... args) {
   myVar.~T(); // free internal memory
   return *new (&myVar) T(args...);
}

emplaceVar(var, 5);

This would solve the problem, but I am not sure if this may cause memory leaks or any other issues I have not thought of due to my lack of experience in c++.这将解决问题,但我不确定这是否会导致内存泄漏或由于我缺乏 C++ 经验而没有想到的任何其他问题。 Furthermore, I would have thought there must be an easier way.此外,我会认为必须有一种更简单的方法。 Is there?有没有?

const members are problematic in general for the very reason you discovered.由于您发现的原因, const成员通常有问题。

The much simpler alternative is to make the member private and take care to provide no means to modify it from outside the class:更简单的选择是将成员设为private并注意不要提供从类外部修改它的方法:

class MyClass {
public:
   MyClass(int a) : a(a) {
   }
   MyClass() : MyClass(0) {
   }
   ~MyClass() {
   }
private:
   int a;
};

I did not add a getter yet, because you say access via myObject.a is a hard requirement.我还没有添加 getter,因为你说通过myObject.a访问是一个硬性要求。 Enabling this requires a bit of boilerplate, but it is much less hacky than modifiying something that must not be modified:启用它需要一些样板文件,但它比修改一些不能修改的东西要少得多:

class MyClass {
public:
   struct property {
       const int& value;
       operator int(){ return value;}
       property(const property&) = delete;
   };

   MyClass(int a = 0) : value(a) {}
private:
   int value;
public:
    property a{value};
};

int main(){
    MyClass myObject{5};
    int x = myObject.a;
    //myObject.a = 42; // error
    //auto y = myObject.a; // unexpected type :/
}

Live Demo现场演示

Drawback is that it does not play well with auto .缺点是它不能很好地与auto If by any means you can accept myObject.a() I would suggest to use that and keep it simple.如果您可以通过任何方式接受myObject.a()我建议使用它并保持简单。

how can I assign a value to var anyway?无论如何,我如何为 var 赋值?

You can do that with a user-defined assignment operator:您可以使用用户定义的赋值运算符来做到这一点:

class MyClass {
public:
   MyClass &operator=(const MyClass &o)
   {
         // Implement your assignment here

         return *this;
   }

   // ...
};

Your assignment operator can do anything that any operator= overload can.您的赋值运算符可以做任何operator=重载可以做的事情。 The only thing it can't do is assign anything to its const class member.它唯一不能做的就是为它的const类成员分配任何东西。 That's because it's constant.那是因为它是恒定的。

If a class does not have user-defined assignment operator, the default assignment operator assigns each member of the assigned-to object from the same member of the assigned-from object.如果一个类没有用户定义的赋值运算符,则默认赋值运算符从被赋值对象的同一成员中分配被赋值对象的每个成员。 However the default assignment operator is deleted from any class that has a const member, because that, of course, is no longer possible.然而,默认赋值运算符会从任何具有const成员的类中删除,因为这当然不再可能。

In your user-defined operator you can do whatever it means to assign one of these objects from another one.在您的用户定义运算符中,您可以做任何事情来从另一个对象分配这些对象之一。 The only thing it can't do is the same thing any other class method can't do: modify a const class member.它唯一不能做的事情与任何其他类方法都不能做的事情是一样的:修改const类成员。

You mentioned manual invocation of a destructor and placement new.您提到了析构函数的手动调用和新的放置。 That's possible, provided that all requisite requirements are met and undefined behavior is carefully avoided.这是可能的,前提是满足所有必要的要求并且小心避免未定义的行为。 However, technically, it wouldn't be assignment, but rather a manual destruction and construction of another object.但是,从技术上讲,这不是赋值,而是手动销毁和构建另一个对象。

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

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