Reputation: 110
I am trying to add a clone func for class A. This class has a non const and not owned pointer b_. I want to make sure that b_ wont be modified in the cloned objects, but it is ok to modify other member variables, and these non-const func in A can still be called.
A bad way is adding a flag and check it every time before modifying b_. It is bad because if a new func in A is added, some one else might forget to check it.
Is there a better way to achieve this goal?
Here is my bad solution mentioned above:
class A {
public:
A* clone() const {
auto* clone = new A(*this);
clone->is_cloned_ = true;
return clone;
}
void DoSomething() {
if (!is_cloned_){
b_->NonConstFunc();
}
}
void DoSomethingElse() {
other_values = 2; // cloned versions can modify this.
}
private:
is_cloned_ = false;
B* b_; // Not owned
int other_values = 1;
}
Upvotes: 2
Views: 81
Reputation: 25388
You could perhaps design a class hierarchy like this:
class cloned_A;
class A
{
public:
cloned_A *clone ();
private:
B* b_;
};
class cloned_A : public A
{
public:
cloned_A (const B *b) : read_only_b (b) {}
private:
const B* read_only_b;
};
cloned_A *A::clone ()
{
return new cloned_A (b_);
}
Now b_
is private to A
and the cloned object can only access read_only_b
via a const
pointer and therefore cannot modify it.
Upvotes: 2
Reputation: 217135
A way to avoid issue when adding method to A
is to wrap the logic to access B
in its own class:
class ProtectedB
{
public:
ProtectedB(B& b) : b(&b) {}
ProtectedB(const ProtectedB& rhs) : b(rhs.b), cloned(true) {}
// Duplicate public B interface
void NonConstFunc() {
if (cloned){ return; }
b->NonConstFunc();
}
// Possibly (might avoid to duplicate non mutable interface of B)
const B& GetB() const { return *b; };
private:
B* b = nullptr;
bool cloned = false;
};
Then A
is simply:
class A {
public:
// ...
std::unique_ptr<A> clone() const { return std::make_unique<A>(*this); }
void DoSomething() { b.NonConstFunc(); }
void DoSomethingElse() { other_values = 2; } // cloned versions can modify this.
private:
ProtectedB b;
int other_values = 1;
};
Upvotes: 0