Take this dummy structure:
struct foo
{
int* pI;
void bar() const
{
int* ptrToI = pI; // I want this to require 'const int*'
*ptrToI = 5; // I want this to fail
}
}__test__;
How can I design this struct to prevent me from changing the value pI points to?
You can use a custom smart pointer in order to hide the underlying pointer:
template <typename T>
struct ptr_t
{
private:
T *ptr;
public:
//Constructors and assignment operators
ptr_t(): ptr(nullptr) {}
ptr_t(T* p): ptr(p) {}
ptr_t(const ptr_t &other): ptr(other.ptr) {}
ptr_t& operator=(T* p) {this->ptr=p;return *this;}
ptr_t& operator=(const ptr_t &other) {this->ptr=other.ptr; return *this;}
//Note that the smart pointers included in the standard returns non-const pointers
//That is why you need to define a custom smart pointer, which forces the const pointer return in the const version of the operators.
const T* operator->() const {return ptr;}
T* operator->() {return ptr;}
const T& operator&() const {return *ptr;}
T& operator&() {return *ptr;}
operator const T*() const {return ptr;}
operator T*() {return ptr;}
};
struct foo2
{
ptr_t<int> pI;
void nonconst_bar()
{
int* ptrToI = pI; // Now success, since not const
*ptrToI = 5;
}
void failing_bar() const
{
//int* ptrToI = pI; // This fails
//*pI = 5; // This also fails
}
void success_bar() const
{
const int* ptrToI = pI;
//*ptrToI = 5; // This is not possible anymore
}
};
Unless you can make the member const int*, you could use inheritance to hide the member from what becomes the child class, and provide a protected function in the base class that yields a const int* pointer:
class base_foo
{
int* pI;
protected:
const int* get_pI(){return pI;}
};
struct foo : base_foo
{
int* ptrToI = get_pI(); // will fail due to attempted conversion to int*
/* and so on*/
Note also that any token containing two consecutive underscores is reserved and as such, formally, the behaviour of your program is undefined: rename __test__.
Related
I was doing some programs on Object Oreinted Programming in C++.
Here is a brief skeleton of the situation
class coll;
class ele {
private:
int val;
coll* p;
public:
ele(int v, coll* p);
int value() const;
friend bool operator==(const ele& El1, const ele& El2);
friend bool operator<(const ele& El1, const ele& El2);
};
class coll {
private:
set<ele> data;
public:
ele* min() const {
if(size()) {
set<ele>::iterator minIt = min_element(data.begin(), data.end());
ele* ptr = &(*minIt);
return ptr;
}
return nullptr;
}
};
In the min() function, the return type has to be non-const and the function has to be const compulsorily.
I don't know why, but min_element's iterator when de-referenced is giving a const reference. Like, &(*minIt) is a const pointer. But I need a non-const pointer to return.
What can be the reason for this behavior. Thanks in advance.
I'm asked to write a SmartPointer class. One of the constructors takes a pointer variable, and I assume that I should simply copy the pointer to the relevant variable. But when I try, I get a segmentation error. Here is the content of the header file and my implementation of Pointer Constructor.
class ReferenceCount {
public:
size_t AddRef() {
return ++count;
}
size_t Release() {
return --count;
}
size_t getCount() const {
return count;
}
private:
size_t count = 0; // Reference count
};
template<typename T>
class SmartPointer {
private:
void free();
// pointer to actual data
T *dataPointer;
// Reference count
ReferenceCount *referenceCount;
public:
//Constructor
SmartPointer();
// Copy constructor
SmartPointer(const SmartPointer<T> &sp);
explicit SmartPointer(T *pValue);
// Assignment operator
SmartPointer<T> &operator=(const SmartPointer<T> &sp);
SmartPointer<T> &operator=(T *pValue);
// Destructor
~SmartPointer();
T &operator*() const;
T *operator->() const;
T *get() const;
ReferenceCount *getReferenceCount() const;
};
The constructor:
template<typename T>
SmartPointer<T>::SmartPointer(T *pValue) {
dataPointer = pValue;
referenceCount = nullptr;
}
You appear to be writing something similar to shared_ptr<T>.
For a shared_ptr-like smart pointer, each smart pointer has both a pointer-to-object and a pointer-to-control-block.
When you are constructed with a pointer-to-object, you are responsible to create the control block.
In your case, your control block name is ReferenceCount.
So add a new ReferenceCount to that constructor. Probably start it off with a count of 1.
I am trying to create a small wrapper-class that lets me use a pointer to a pointer like
it was just a normal pointer(just for convenience).
I came up with the following code:
template<typename T>
class PtrPtr
{
public:
PtrPtr() = default;
PtrPtr(const T** ptr) : m_ptr(ptr) { }
inline void operator =(const T** ptr) { m_ptr = ptr; }
inline void operator =(T** ptr) { m_ptr = ptr; }
inline operator T*() const { return (*m_ptr); }
inline T** get() const { return m_ptr; }
private:
T** m_ptr;
};
I thought the operator inline operator T*() const { return (*m_ptr); } would
make it possible to use the class as if it were a pointer to T, however it doesn't seem to work
when I try to access T's elements with the following syntax:
PtrPtr<myStruct> ptr = function that returns a pointer to pointer to myStruct;
ptr->some member of myStruct; <-Gives an error
static_cast<myStruct*>(ptr)->some member of myStruct; <-works but obviously tedious syntax
Note that when I specifically cast "PtrPtr ptr" to a T* and then try to access its
members with the "->"-operator it seems to work.
Any Ideas if it is possible to acheive a clean syntax here?
The solution is to over load the ->-operator.
This thread explains how it is done.
How do i fix this?
I'm getting error: 'this' argument has type const but function is not marked const c++ overload operator
template <class T>
class Rational {
private:
T n = 0;
T d = 1;
public:
Rational() = default;
T numerator() {
return n;
}
T denominator() {
return d;
}
};
template <class T>
inline bool const operator ==(const Rational <T> & lhs, const Rational <T>& rhs) {
return lhs.numerator() * rhs.denominator() == lhs.denominator() * rhs.numerator();
}
My guess is that numerator() and denominator() member functions are not const member functions. Make them const. After that, the above function should work.
BTW, there is no need for the return type to be bool const. Keep it simple and change it to bool.
If numerator() and denominator() are to be used to directly assign to Rationals internal member variables as well as being used in const contexts, you need two sets of overloads. One mutable and one const:
// mutable interface
T& Rational::numerator();
T& Rational::denominator();
// const interface if T may only be a fundamental integral type
T Rational::numerator() const;
T Rational::denominator() const;
// const interface if sizeof(T) may be > sizeof(T*)
T const& Rational::numerator() const;
T const& Rational::denominator() const;
Note, only one of the const interfaces may be used so you need to select one of them.
Here's an example of how it can be done:
#include <iostream>
#include <type_traits>
template<typename T>
class Rational {
public:
// pass by value for fundamental types, by const& for other types
using by_value_or_by_const_ref =
std::conditional_t<std::is_fundamental_v<T>, T, T const&>;
Rational(by_value_or_by_const_ref n, by_value_or_by_const_ref d) :
m_numerator(n), m_denominator(d) {}
// mutable interface
T& numerator() { return m_numerator; }
T& denominator() { return m_denominator; }
// const interface
by_value_or_by_const_ref numerator() const { return m_numerator; }
by_value_or_by_const_ref denominator() const { return m_denominator; }
private:
T m_numerator;
T m_denominator;
};
template<class T>
inline bool operator==(const Rational<T>& lhs, const Rational<T>& rhs) {
// using const interface
return lhs.numerator() * rhs.denominator() ==
lhs.denominator() * rhs.numerator();
}
int main() {
Rational<int> a(10, 20);
Rational<int> b(10, 10);
// using mutable interface
a.denominator() /= 4;
b.numerator() *= 2;
std::cout << std::boolalpha << (a == b) << "\n";
}
I want to convert numerous similar classes into each other. They have at least a common abstract ancestor, which defines 2 basic methods.
I ran into weird typecast errors, so I made a simplified example. On top of the hierarchy: the Integer class. It's an abstract class that have an int val() method. One of it's child is just a holder for a physical int value, while the other references 2 Integers and val() is the sum of its two referenced Integers.
I wrote this code, and I could not figure why the commented expression fails to compile while using a temporary variable works just great.
class Sum;
class Integer {
public:
virtual int val(void) const = 0;
Sum operator+(Integer & other);
};
class Sum : public Integer {
private:
Integer &op1, &op2;
public:
explicit Sum(Integer &a, Integer &b) : op1(a), op2(b) {};
int val(void) const {return op1.val() + op2.val();};
};
class Int : public Integer {
private:
int v;
public:
Int(int value=0) : v(value) {};
Int(Integer & other) : v(other.val()) {};
int val() const {return v;};
Int & operator=(Integer & other){v = other.val(); return *this;};
Int & operator=(int value){v = value; return *this;};
};
std::ostream & operator<<(std::ostream & out, Integer & i){return out << i.val();}
Sum Integer::operator+(Integer & other){return Sum(*this, other);}
int main(int argc, const char **argv){
Int a=42, b=57;
// Int s = a+b; => conversion from ‘Sum’ to non-scalar type ‘Int’ requested
Sum r = a+b;
Int s = r; /* OK */
cout << a << " + " << b << " = " << s << endl;
return 0;
}
class Int : public Integer {
private:
int v;
public:
Int(int value=0) : v(value) {};
Int(Integer & other) : v(other.val()) {};
int val() const {return v;};
Int & operator=(Integer & other){v = other.val(); return *this;};
Int & operator=(int value){v = value; return *this;};
};
The constructor Int(Integer & other) doesn't modify its argument, so could (should) make that reference const:
Int(Integer const& other) : v(other.val()) {};
This also solves your problem:
Sum Integer::operator+(Integer & other);
Int s = a+b;
The operator + (which should arguably be a free function instead of a member function) returns a prvalue/temporary of type Sum. This temporary cannot bind to a non-const lvalue reference, therefore the constructor Int(Integer & other) cannot be used.
Similarly for Int & operator=(Integer & other), a const reference is sufficient.
For functions that take non-const references, like your constructor for Int, you cannot pass temporary objects. A common explanation for this is because if you a function takes a non-const reference, it is allowed to modify the referent, but with a temporary object, this change doesn't really go anywhere since the referent variable isn't accessible outside of the function call.
As DyP suggests in the comments, changing the value to const will provide a solution, or you could simply bind it to a variable like you did with 'Sum r = a+b'.