How can I make a class, which is sometimes readonly, and sometimes writable? One option is with getter/setters and a flag which indicates if the object is read-only, but that is a lot of overhead. I also desire this readonly property to work deeply on the object, making sure that all of the objects it contains are also readonly or writeable. Here's some example code of the desired behavior which I tried but failed to achieve using const.
This question is quite generic, so has probably been asked before, but I wasn't able to find a good solution to this exact problem on stackoverflow.
Example code:
https://ideone.com/4cXyNF
class InnerClass {
public:
InnerClass(int j) : j_(j) {}
int j_;
};
class OuterClass {
public:
OuterClass(int i, InnerClass& c) : i_(i), reference_(c), pointer_(&c) {}
int i_;
InnerClass& reference_;
InnerClass* pointer_;
};
int main() {
InnerClass c(1);
OuterClass readwrite(2, c);
// Desire these 3 operations to work on the writable object
readwrite.i_ = 3;
readwrite.reference_.j_ = 4;
readwrite.pointer_->j_ = 5;
const OuterClass readonly(6, c);
// COMPILER ERROR: error: assignment of member 'OuterClass::i_'
// in read-only object
// readonly.i_ = 7;
// Desire this to be a compiler error, but it isn't
readonly.reference_.j_ = 8;
// Desire this to be a compiler error, but it isn't
readonly.pointer_->j_ = 9;
return 0;
}
If you change your members to functions, you can create const overloads of the methods like this
class InnerClass {
public:
explicit
InnerClass(int j) : j_(j) {}
int& j() { return j_; }
const int& j() const { return j_; }
private:
int j_;
};
class OuterClass {
public:
OuterClass(int i, InnerClass& c) : i_(i), reference_(c), pointer_(&c) {}
int& i() { return i_; }
const int& i() const { return i_; }
InnerClass const& reference() const { return reference_; };
InnerClass & reference() { return reference_; };
InnerClass const* pointer() const { return pointer_; };
InnerClass * pointer() { return pointer_; };
private:
int i_;
InnerClass& reference_;
InnerClass* pointer_;
};
int main() {
InnerClass c(1);
OuterClass readwrite(2, c);
// Desire these 3 operations to work on the writable object
readwrite.i() = 3;
readwrite.reference().j() = 4;
readwrite.pointer()->j() = 5;
const OuterClass readonly(6, c);
// COMPILER ERROR: error: assignment of member 'OuterClass::i_'
// in read-only object
readonly.i_ = 7;
// Desire this to be a compiler error, and it is
readonly.reference().j() = 8;
// Desire this to be a compiler error, and it is
readonly.pointer()->j() = 9;
return 0;
}
Live on Coliru
You can achieve this by using member functions to return the references / pointers const if the object itself is const.
class InnerClass {
public:
InnerClass(int j) : j_(j) {}
int j_;
};
class OuterClass
{
InnerClass& reference_;
public:
OuterClass(int i, InnerClass& c) : i_(i), reference_(c) {}
int i_;
InnerClass & in() { return reference_; }
InnerClass const & in() const { return reference_; }
};
Now neither i_ nor in().j_ is writable in case outer is const:
InnerClass i{ 1 };
OuterClass write(2, i);
write.i_ = 3; // works
write.in().j_ = 3; // works
OuterClass const read(2, i);
read.i_ = 3; // error!
read.in().j_ = 3; // error!
This is a similar solution as some else already posted, but uses a slightly different approach:
class InnerClass {
public:
InnerClass(int j) : j_(j) {}
int j_;
};
template<bool readOnly>
class OuterClass{
public:
OuterClass(int i, InnerClass& c) : i_(i), reference_(c), pointer_(&c) {}
int i_;
typename std::conditional<readOnly,const InnerClass&, InnerClass&>::type reference_;
typename std::conditional<readOnly,const InnerClass* const, InnerClass*>::type pointer_;
};
int main(int argc,char** args){
InnerClass c(1);
OuterClass<true> readonly(12,c);
//readonly.reference_.j_ = 1; //Error "reference_ is read only"
//readonly.pointer_->j_ = 1; //Error "pointer_ is read only"
OuterClass<false> write(12,c);
write.reference_.j_ = 1;
write.pointer_->j_ = 1;
}
Related
The class TestConst has a member set of type std::function<void(double)>.
The setter method is marked as const but it still modifies the internal private variable m_value.
class TestConst {
public:
void setter(double v) const {
set(v);
}
private:
double m_value = 1;
std::function<void(double)> set = [this](double v) {m_value = v;};
};
Why does the compiler (g++ 10.2) allows that without any errors or warnings?
The capture of this isn't const, and the member isn't modified by *this but through an indirection.
This is the same situation:
class TestConst {
public:
void setter(double v) const {
sneaky.set(v);
}
private:
double m_value = 1;
struct
{
TestConst* that;
void set(double v) const { that->m_value = v; }
} sneaky{ this };
};
The code below is a simplified version of the actual problem I am facing.
Assume I do not have permission to modify class A (as it is external library), and its already widely used in my existing code base.
The const & assignment from a temporary object (direct constructor) which also return a const & member variable via implicit conversion is not valid in this case.
How do I prevent or make it legal in this case so that the caller gets the correct A value?
class A
{
public:
A() { }
A(int _r, int _g, int _b)
: r(_r), g(_g), b(_b)
{
}
~A(){ }
int GetR() const { return r; }
int GetG() const { return g; }
int GetB() const { return b; }
private:
int r = 0;
int g = 0;
int b = 0;
};
class Foo
{
public:
Foo() : Foo(A()) {}
Foo(int _r, int _g, int _b) : a(A(_r, _g, _b)) {}
explicit Foo(const A& _a) : a(_a) {}
Foo& operator=(const A& a)
{
*this = Foo(a);
return *this;
}
operator A() const { return a; }
operator const A&() const { return a; }
private:
A a;
};
int main()
{
const A& a = Foo(200, 100, 300);
std::cout << a.GetR() << a.GetG() << a.GetB() << endl; // I may not get 200 100 300 here as Foo is already out of scope
return 0;
}
Motivation
Some background on why I am implementing a class as above. The actual purpose of class Foo is to contain 2 different objects, which actually has the same purpose, just different way of storing data internally. For example, let's say class A and class B, which stores RGB value of color in int and floating (normalized) respectively. And as mentioned above, I do not have permission to modify class A, and its already widely used in my code base.
There are tons of function in my code base which takes in const A& and const B& as a function param. So I am trying to unify this 2 classes for a particular case, where I can just pass in Foo in those places and it will work as expected.
You can apply ref-qualified member functions (since C++11), i.e. mark the conversion operator with lvalue-reference, to prevent it being called on temporaries (rvalues).
class Foo
{
public:
... ...
operator A() const { return a; }
operator const A&() const & { return a; }
operator const A&() && = delete;
... ...
};
Then
const A& a = Foo(200, 100, 300); // invalid; invokes deleted operator
const A& a = static_cast<A>(Foo(200, 100, 300)); // fine; invokes operator A()
Is the following code valid C++? Otherwise, is there a valid way to simultaneously interpret memory as values of different type?
#include <cstdio>
struct Base { int payload; };
struct D1 : Base { void operator()(){ printf("D1: %d\n", payload);} };
struct D2 : Base { void operator()(){ printf("D2: %d\n", payload);} };
int main()
{
D1 d1;
D2& d2 = static_cast<D2&>(static_cast<Base&>(d1));
d1();
d2();
d2.payload = 3;
d1();
d2();
}
In response to #NickoPo: My use case is basically what follows. Imagine that IntBase is not necessarily cheap to copy, that there are many complex algorithms, some of which profit from numbers being prime vs. odd, and others don't:
#include <cassert>
#include <cstdio>
bool is_odd(int value) { return 0 != value % 2; }
bool is_small_prime(int value) { return 2 == value || 3 == value || 5 == value || 7 == value; }
class IntBase
{
public:
explicit IntBase(int value) : m_value(value) {}
int value() const { return m_value; }
protected:
int m_value;
};
class OddInt : public IntBase
{
public:
explicit OddInt(int value) : IntBase(value) { assert(is_odd(m_value)); }
};
class SmallPrimeInt : public IntBase
{
public:
explicit SmallPrimeInt(int value) : IntBase(value) { assert(is_small_prime(m_value)); }
};
bool is_constrainable_to_odd_int(IntBase const& x)
{
return is_odd(x.value());
}
OddInt const& constrain_to_odd_int(IntBase const& x)
{
assert(is_odd(x.value()));
return static_cast<OddInt const&>(x);
}
bool is_constrainable_to_small_prime_int(IntBase const& x)
{
return is_small_prime(x.value());
}
SmallPrimeInt const& constrain_to_small_prime_int(IntBase const& x)
{
assert(is_small_prime(x.value()));
return static_cast<SmallPrimeInt const&>(x);
}
void algorithm(IntBase const&)
{
printf("algoritm(IntBase const&)\n");
}
void algorithm(OddInt const&)
{
printf("algoritm(OddInt const&)\n");
}
void algorithm(SmallPrimeInt const&)
{
printf("algoritm(SmallPrimeInt const&)\n");
}
void test(IntBase const& x)
{
if (is_constrainable_to_small_prime_int(x))
{
algorithm(constrain_to_small_prime_int(x));
}
else if (is_constrainable_to_odd_int(x))
{
algorithm(constrain_to_odd_int(x));
}
else
{
algorithm(x);
}
}
void test(OddInt const& x)
{
if (is_constrainable_to_small_prime_int(x))
{
algorithm(constrain_to_small_prime_int(x));
}
else
{
algorithm(constrain_to_odd_int(x));
}
}
int main()
{
IntBase x(0);
OddInt y(1);
OddInt z(7);
test(x); // algoritm(IntBase const&)
test(y); // algoritm(OddInt const&)
test(z); // algoritm(SmallPrimeInt const&)
}
Related:
Can I legally reinterpret_cast between layout-compatible standard-layout types?
Answer to Safety of casting between pointers of two identical classes?
If you're going to cast while using similar interfaces while using type as a guarantee, I'd recommend that you just wrap the inner data with your new object type and then provide access to the inner data in order to transfer it from one type to another. There's no point in doing static casting or reinterpret casting if you're not going to do it safely.
Here's an example:
http://coliru.stacked-crooked.com/a/40d5efeff22fcdcd
#include <iostream>
//Base data structure to encapsulate only data.
struct data {
data(int i) : i(i) {}
int i;
};
//Wrapper around our data structure, with interfaces to access
//the values and the data; implement your own constructor to
//gate the value
class PrimeInt {
public:
PrimeInt(const int i)
: d(i) {}
PrimeInt(const data& other)
: d(other) {}
PrimeInt(data&& other)
: d(std::move(other)) {}
PrimeInt& operator=(const PrimeInt&) = default;
PrimeInt& operator=(PrimeInt&&) = default;
int get() {return d.i;};
operator data() {return d;};
private:
data d;
};
//Wrapper around our data structure, with interfaces to access
//the values and the data; implement your own constructor to
//gate the value
class OddInt {
public:
OddInt(const int i)
: d(i) {}
OddInt(const data& other)
: d(other) {}
OddInt(data&& other)
: d(std::move(other)) {}
OddInt& operator=(const OddInt&) = default;
OddInt& operator=(OddInt&&) = default;
int get() {return d.i;};
operator data() {return d;};
private:
data d;
};
//Notice that we can now implicitly cast from one type to another.
int main() {
PrimeInt pi(10);
std::cout << pi.get() << std::endl;
OddInt oi(pi);
std::cout << oi.get() << std::endl;
return 0;
}
If your objects are not cheap to copy, you are probably passing pointers or references everywhere. You can wrap pointers to your common base in different class types and pass them by value. That is, instead of this (pseudocode)
class B
class D1 : B { ... }
class D2 : B { ... }
D1* d1; D2* d2;
you have
class Bimpl
class B { Bimpl* bimpl; }
class D1 : B { ... }
class D2 : B { ... }
D1 d1; D2 d2;
Here you never do any built-in cast. If you want to convert D1 to D2, you write your own conversion function.
Hi, I've created a class which has three constructors, two integer members & one const int member. So for one constructor I'm using initializer list to assign const int member but I am getting error in other two constructors
Here is my code:
class base
{
public:
base();
base(const int _count);
base(int a ,int b);
~base();
protected:
int m_ia , m_ib;
const int count;
};
base::base()
{
}
base::base(const int _count):count(_count)
{
}
base::base(int a , int b)
{
m_ia = a ;
m_ib = b;
}
base::~base()
{
}
void main()
{
base *obj2 = new base(1000);
getchar();
}
Number of Errors:2
1.'base::count' : must be initialized in constructor base/member initializer list at base()
2.'base::count' : must be initialized in constructor base/member initializer list at base(int a ,int b)
You should probably make sure all your constructors are initializing all member variables, not just the one's being passed in as arguments. I'd rewrite your constructors as
base::base()
: m_ia() // value initializes i.e. sets to 0
, m_ib()
, count()
{
}
base::base(const int _count)
: m_ia()
, m_ib()
,count(_count)
{
}
base::base(int a , int b)
: m_ia(a)
, m_ib(b)
, count()
{
}
And if you have a C++11 compiler that supports delegating constructors, you could create a 4 constructor that takes 3 arguments and have the other constructors delegate to that one.
base::base()
: base(0, 0, 0)
{
}
base::base(const int _count)
: base(0, 0, _count)
{
}
base::base(int a , int b)
: base(a, b, 0)
{
}
base::base(int a , int b, int count)
: m_ia(a)
, m_ib(b)
, count(count)
{
}
The last constructor can be made private if you don't want it to be part of the class interface.
In c++11 you can have
protected:
int m_ia , m_ib;
const int count = 0;
It works in VS 2013.
As per standard C++ and you current code you have to Initialize your const variable in constructor using initialize list so code can be modified as below :
#include"iostream"
using namespace std;
class base
{
public:
base();
base(const int _count);
base(int a ,int b, const int _count);
~base();
protected:
int m_ia , m_ib;
const int count;
};
base::base():count(0)
{
}
base::base(const int _count):count(_count)
{
}
base::base(int a , int b, const int _count):count(0)
{
m_ia = a;
m_ib = b;
}
base::~base()
{
}
int main()
{
base *obj2 = new base(1000);
getchar();
return 0;
}
in C++ is it a bad practice to use reference in place of getters?
for example:
class X
{
int mP;
public:
const int& P;
X():P(mP){}
};
and later
X xl;
int h = xl.P;
Just think about refactoring to make the access thread safe, that won't work well this way and require a lot of changes in the client classes/functions.
If you have class members, that are guaranteed not to be changed over lifetime of the instance, you can simply provide const int P; and initialize it properly in your class' constructors.
If the value is to be visible class wide use a static const int P;
In any other case use a public getter:
int P() const; // a return type of 'const int &' would be redundant
1st shot implementation:
int X::P() const
{
return mP;
}
Thread safe implementation:
class X {
{
// ...
private:
// ...
mutable std::mutex internalDataGuard;
};
int X::P() const
{
std::lock(internalDataGuard);
return mP;
}
None of this is good:
class X { public: int x; };
class X {
private: int m_x;
public: const int& get() const { return m_x; }
public: void set(const int& other) { m_x = other; }
};
class X {
private: int m_x;
public: const int& x() const { return m_x; }
public: void x(const int& other) { m_x = other; }
};
class X {
private: int m_x;
public: const int& x() const { return m_x; }
public: int& x() { return m_x; }
};
Pick one, it's a design decision.
Having 'const int& x' to publish the private member will work:
class X {
private: int m_x;
public: const int& x;
public: X() : m_x(0), x(m_x) {}
// Take care for copy and assignment
};
The cost is a larger memory footprint.