简体   繁体   English

Const和非const c ++构造函数

[英]Const and non-const c++ constructor

Is there a way in C++03 (or earlier) to write a class that can either store a const or non-const pointer, and handles access appropriately? 在C ++ 03(或更早版本)中是否有一种方法可以编写一个可以存储const或非const指针的类,并适当地处理访问? Take the usage of the non-functional "SometimesConst" class as an example: 以非功能“有时会话”类的使用为例:

class SometimesConst
{
    public:
    SometimesConst(int * buffer) : buffer(buffer) {} // Needs const qualifier?

    int* get() { return buffer; } // Needs const qualifier?

    void increment() { counter++; }

    private:
    int * buffer; // Needs const qualifier?
    int counter;
};

void function(int * n, const int * c)
{
    // These are both okay
    SometimesConst wn(n);
    SometimesConst wc(c);

    // Reading the value is always allowed
    printf("%d %d", wn.get()[0], wc.get()[0]);

    // Can increment either object's counter
    wn.increment();
    wc.increment();

    // Can set non-const pointer
    wn.get()[0] = 5;

    // Should generate a compiler error
    wc.get()[0] = 5;
}

Creating a const SometimesConst would not allow modification of the counter property of the object. 创建const SometimesConst不允许修改对象的counter属性。 Can a class be designed that has compile-time const safety for input objects, only if they are passed in as const? 是否可以设计一个类对输入对象具有编译时const安全性的类,只有它们作为const传入?

No, not the way you are wanting to use it. 不,不是你想要使用它的方式。 The only way to have different behavior at compile time is to have different types. 在编译时具有不同行为的唯一方法是使用不同的类型。 However, you can make that fairly easy to use: 但是,您可以使用起来相当容易:

#include <stdio.h>

template <typename T>
class SometimesConst
{
  public:
    SometimesConst(T* buffer) : buffer(buffer) { }
    T* get() { return buffer; }
    void increment() { ++counter; }
  private:
    T *buffer;
    int counter;
};

typedef SometimesConst<const int> IsConst;
typedef SometimesConst<int> IsNotConst;

void function(int * n, const int * c)
{
  IsNotConst wn(n);
  IsConst wc(c);

  // Reading the value is always allowed
  printf("%d %d", wn.get()[0], wc.get()[0]);

  // Can increment either object's counter
  wn.increment();
  wc.increment();

  // Can set non-const pointer
  wn.get()[0] = 5;

  // Should generate a compiler error
  wc.get()[0] = 5;
}

The language already mostly lets you do this with a simple class; 该语言已经主要允许您使用简单的类来完成此操作; with the way const cascades to access to members (combined with mutable for the counter member, which you've indicated should always be mutable), you can provide both read-only and read-write access to a buffer quite easily: 使用const级联访问成员的方式(与counter成员的mutable相结合,你已经表明它应该是可变的),你可以很容易地提供对缓冲区的只读和读写访问:

class C
{
public:
    C(int* buffer) : buffer(buffer) {}

    const int* get() const { return buffer; }
    int* get() { return buffer; }

    void increment() const { counter++; }

private:
    int* buffer;
    mutable int counter;
};

void function(int* n)
{
    // These are both okay
    C wn(n);
    const C wc(n);

    // Reading the value is always allowed
    printf("%d %d", wn.get()[0], wc.get()[0]);

    // Can increment either object's counter
    wn.increment();
    wc.increment();

    // Can set non-const pointer
    wn.get()[0] = 5;

    // Generates a compiler error
    wc.get()[0] = 5;
}

What you can't do with this is neatly arrange for the class to be instantiated with either a int* or a const int* ; 你不能用这个做的类排列整齐与无论是被实例化int*const int* ; the two lead to totally different semantics for your class, so you should split it into two if you really need that. 这两个导致你的班级完全不同的语义,所以你应该把它分成两个,如果你真的需要它。

Fortunately, templates make this easy: 幸运的是,模板使这很容易:

template <typename T>
class C
{
public:
    C(T* buffer) : buffer(buffer) {}

    const T* get() const { return buffer; }
    T* get() { return buffer; }

    void increment() const { counter++; }

private:
    T* buffer;
    mutable int counter;
};

Now a C<int> is as above, but a C<const int> only provides read-only access to the buffer, even when the C<const int> object itself is not marked as const : 现在C<int>如上所述,但C<const int> 提供对缓冲区的只读访问,即使C<const int>对象本身未标记为const

void function(int* n1, const int* n2)
{
    C<int>             a(n1);
    C<const int>       b(n2);
    const C<int>       c(n1);
    const C<const int> d(n2);

    // Reading the value is always allowed
    printf("%d %d %d %d",
       a.get()[0], b.get()[0],
       c.get()[0], d.get()[0]
    );

    // Incrementing the counter is always allowed
    a.increment();
    b.increment();
    c.increment();
    d.increment();

    // Can set non-const pointer
    a.get()[0] = 5;

    // Cannot set const pointer, or const/non-const pointer behind const object
    //b.get()[0] = 5;
    //c.get()[0] = 5;
    //d.get()[0] = 5;
}

Live demo 现场演示

I think that there is a design problem if you want to store two different things which must be handled in different ways in one class. 我认为如果你想存储两个必须在一个类中以不同方式处理的不同的东西,那么存在设计问题。 But yes, you can do it: 但是,你可以这样做:

struct X{};

class A
{   
    public:
        A(const X*) { cout << "const" << endl; }
        A(X*)       { cout << "non const" << endl; }

};  

int main()
{   
    const X x1; 
    X x2; 

    A a1(&x1);
    A a2(&x2);
}   

the output is expected: 输出是预期的:

const
non const

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

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