Home > Back-end >  How to design a class with const, non const member function and it can take over const raw pointer?
How to design a class with const, non const member function and it can take over const raw pointer?

Time:11-12

I have a class, it can define some operations on a raw pointer.

For example, the class is called Vector.

class Vector
{
public:
    explicit Vector(double *ptr_, int size_)
       :ptr(ptr_), size(size_)
    {
        
    }
    // some operation change data in ptr
    void notConstOperation()
    {
        ptr[0]=ptr[0] 1;
    }
    // some operation do not change data in ptr
    double constOperation() const
    {
        return ptr[0];
    }
private:
    double *ptr;
    int size;
};

And I have a lot of others operations on Vector

int doNotConstOperation(Vector &vec);
int doConstOperation(const Vector &vec);

My problem is, I find I can not create the Vector object from a raw const pointer.

Vector createVectorFromNonConstPtr(const *ptr, int size)
{
    // ok.
    return Vector(ptr, size);
}
Vector createVectorFromConstPtr(const double *ptr, int size)
{
    // can not create, because the args in Vector is not const.
    return Vector(ptr, size);
}

I want to use the Vector in the follow way:

// using const ptr
const double *cptr; 
const Vector cvec = createVectorFromConstPtr(cptr, 10);
cvec.constOperation();
doConstOperation(cvec);

// using non-const ptr
const double *ptr; 
Vector vec = createVectorFromPtr(cptr, 10);
vec.notConstOperation();
doNotConstOperation(vec);

I know splitting the class into Vector and ConstVector can help.

But it leads to some verbose, the const operation will be written twice.

How can I implement that?

Any suggestion is I looking forward. Thanks for your time.

CodePudding user response:

Any suggestion is I looking forward

Inheritance.

class ConstVector {
   const double *ptr;
protected:
   double *_ptr() {
        return const_cast<double *>(ptr);
   }
   void _set_ptr(double *new_ptr) {
        ptr = new_ptr;
   }       
   friend Vector;
};
class Vector : ConstVector {
     // some operation change data in ptr
    using ConstVector::ConstVector;
    void notConstOperation() {
        // _ptr() is inherited.
        _ptr()[0] = _ptr()[0] 1;
    }
}

Template overload.

template<bool isconst>
class Vector {
   double *ptr;
   Vector(double *ptr) : ptr(ptr) {}
   template<int empty = 1>
   Vector(const double *ptr,
        typename std::enable_if<isconst && empty>::type* = 0
        ) : ptr(const_cast<double *>(ptr)) {}
   typename std::enable_if<!isconst>::type notConstOperation() {
       ptr[0] = ptr[0]   1;
   }
};

Runtime tracking.

   class Vector {
       bool isconst;
       double *ptr;
       Vector(double *ptr) : ptr(ptr), isconst(0) {}
       Vector(const double *ptr) : ptr(const_cast<double *>(ptr)), isconst(1) {}
       void  notConstOperation() {
          assert(!isconst);
          ....
       }
   };

Or return a const vector and const cast to construct it:

class Vector
{
public:
    Vector(double *ptr, int size)
       : ptr(ptr), size(size) {}
    void notConstOperation() { .... }
    double constOperation() const { ... }
private:
    double *ptr;
    int size;
};

Vector createVectorFromNonConstPtr(double *ptr, int size)
{
    return Vector(ptr, size);
}
const Vector createVectorFromConstPtr(const double *ptr, int size)
{
    return Vector(const_cast<double*>(ptr), size);
}

CodePudding user response:

a const double* pointer is a pointer which preserve the value of the variable it is pointing to. The class Vector has (among its purposes) ways to change the value pointed to by this pointer. In short, the const qualifier is a kind of programmer's rule. The rule is : You can't change the value of the variable.

The compiler detect your attempt to manipulate the variable with objects that might change its value and consider it an error.

The problems start as soon as the compiler assigns to your member ptr (which is not aconst double *but adouble *) the value of your variable const double * ptr. This assignment can't happen since you can't assign to a double* the value of a const double*.

You can basically try to compile the following example.

int main() {
    const double* ptr = nullptr;
    double* error = ptr;
}

a const_cast<double*> could solve this issue.

int main() {
    const double* ptr = nullptr;
    double* ok = const_cast<double*>(ptr);
}

I personally don't like const_cast with removing const qualifier to the type, i think i would prefer to make two classes : class VectorView and class Vector which inherit the first.

  •  Tags:  
  • c
  • Related