I have this class hierarchy where I'm trying to add operator= :
class A
{
public:
virtual void someFunction() = 0;
virtual A& operator=(const A&) = 0;
};
class B : public A
{
public:
void someFunction() {
//implementation
}
A& operator=(const A& o)
{
*ptr = *o.ptr;
return *this;
}
private:
A* ptr;
};
class C : public A
{
public:
void someFunction() {
//implementation
}
A& operator=(const A& o)
{
data = o.data;
return *this;
}
private:
int data; //NOTE: different members that needs to be copied in the operator
};
I understand why this doesn't work. I have a private member in B (that needs to be there) and a function A&operator=(const A&) that needs to be overwritten. Problem is that o is of type A and doesn't have the pointer ptr.
I've tried to dynamic_cast o to type B, but
that wont work since it's constant,
It seems unsafe (if rhs is of type C)
Same issue for class C.
Is there some cleaver work-around?
Clarification of why I need it this way:
class superClass
{
public:
superClass& operator=(const superClass& o)
{
*some_A_type = *o.some_A_type;
}
private:
A* some_A_type;
};
essentially, what I want is an operator= for superClass. I'm not sure where or how to fix it.
You should re-consider your initial design of classes.
Also you should understand:
operator polymorphism (a + b works for both std::string and int)
data type cannot be polymorph by itself because memory layout should be defined
what is abstract class and/or interface
maybe static polymorphism would be useful too
First try to imagine what implication of having assignment between any object of any class within class A. I.e. to store object of B in object of C we should change state of object from C in that way that its characteristics will be equivalent object to original object from B. This can be achieved either by having common memory layout (i.e. all descendants store same data) between all descendants of A or by exposing same behavior in some other way like referencing to original object.
Note that behavior of virtual void someFunction() should also be copied.
Let's try to pull out maximum out of your sample:
// our interface
struct A {
virtual void someFunction() = 0;
// no polymorphic assignment
};
struct B : A {
void someFunction();
B &operator=(const A &o)
{ ptr = &o; return *this; }
private:
A *ptr;
}
struct C : A {
void someFunction();
A &operator=(const C &o)
{ data = o.data; return *this; }
private:
int data;
};
C c, c2;
B b;
A &a = c;
b = c; // ok
b = a; // ok
c = c2; // ok
c = b; // wrong
Or if you still want polymorphic assignment:
// interface. descendants are responsible for maintaining LSP
struct A {
void someFunction()
{ cout << data(); }
virtual int getData() const = 0;
// assignment should result in copying chars and making getData() to behave like in original object
virtual A &operator=(const A &o) = 0;
};
struct B : A {
int getData() const { return ptr->getData(); }
A &operator=(const A &o)
{ ptr = &o; return *this; }
private:
const A *ptr;
};
struct C : A {
int getData() const { return data; }
A &operator=(const A &o)
{ data = o.getData(); return *this; }
private:
int data;
};
P.S. Last variant probably unwanted in real world.
Found in similiar question sugested by TobiMcNamobi:
class B : public A
{
public:
virtual A& operator=(const A& p)
{
*ptr = *o.ptr;
return *this;
}
virtual B& operator=(const B& p)
{
//throw exception
}
};
Related
I have class A with disabled copy semantics and class B which contains vector of A's. How can I write a member function of B that returns reference to the vector of A's?.
For those knowing Rust here is what I am trying to do (expressed in the Rust language):
struct A {/* ... */}
struct B {
data: Vec<A>,
}
impl B {
pub fn data(&self) -> &Vec<A> {
&self.data
}
}
As #molbdnilo stated my error was that I used auto data = b.data(); instead of auto& data = b.data();. Therefore following example is working and shows how to do what I asked:
#include<vector>
class A
{
public:
A(const A&) = delete;
A(A&&) = default;
A& operator=(const A&) = delete;
A& operator=(A&&) = default;
private:
/* some data */
};
class B
{
public:
B(): m_data {} {}
const std::vector<A>& data() const {
return this->m_data;
}
private:
std::vector<A> m_data;
};
int main()
{
auto b = B();
auto& data = b.data();
}
In the following example we have a class Class that contains a Bridge object that takes care of all the memory handling for us (rule of three).
class Base {
public:
Base() {};
virtual Base* clone() const = 0;
virtual ~Base() {};
};
class Derived : public Base {
public:
Derived() {};
virtual Base* clone() const {
return new Derived(*this);
}
virtual ~Derived() {}
};
class Bridge {
public:
Bridge(const Bridge& bridge_) {
base = bridge_.base->clone();
}
Bridge(const Base& base_) {
base = base_.clone();
}
~Bridge() { delete base; }
Bridge& operator=(const Bridge& assignFrom) {
if(this != &assignFrom) {
delete base;
base = assignFrom.base->clone();
}
return *this;
}
private:
Base *base;
};
class Class {
public:
Class(const Bridge& bridge_) : bridge(bridge_) {};
private:
Bridge bridge;
};
int main()
{
Derived derived;
Class c(derived);
Class c1(c);
}
Now, I have just learned about smart pointers and was trying to recreate the above example using unique_ptr. To my understanding, we basically don't need to implement the rule of 3 ourselves as the smart pointer contains it already. To test this, I made the following example:
class BaseSMRT {
public:
BaseSMRT() {};
virtual std::unique_ptr<BaseSMRT> clone() const = 0;
virtual ~BaseSMRT() {};
};
class DerivedSMRT : public BaseSMRT {
public:
DerivedSMRT() {};
virtual std::unique_ptr<BaseSMRT> clone() const {
return std::make_unique<DerivedSMRT>(*this);
}
virtual ~DerivedSMRT() {}
};
class ClassSMRT {
public:
ClassSMRT(const BaseSMRT& base) {
ptr = base.clone();
};
private:
std::unique_ptr<BaseSMRT> ptr;
};
int main()
{
DerivedSMRT derivedSMRT;
ClassSMRT cSMRT(derivedSMRT);
ClassSMRT cSMRT2(cSMRT); // error: Call to implicitly-deleted copy constructor of 'ClassSMRT'
}
As you can see in the above example, initialising cSMRT2 with cSMRT through the copy constructor doesn't work and gives me the above error.
I don't get this: Why is it that I can call Class's default copy constructor like this, Class c1(c);, but not call ClassSMRT's default copy constructor, ClassSMRT cSMRT2(cSMRT);?
This suggests that the rule of three isn't already implemented for us when we are using unique_ptr.
unique_ptr is designed to stop accidental copies. You want to implicitly clone you polymorphic type when copied. unique_ptr doesn't (directly) fit your uses.
I would suggest a rename of Bridge
template </*Cloneable*/ typename T>
class clone_ptr {
public:
clone_ptr(const T& base_)
: base(base_.clone()) {}
clone_ptr(const clone_ptr& other)
: base(other.base->clone()) {}
clone_ptr(clone_ptr&& other) = default;
clone_ptr& operator=(clone_ptr other) {
base = std::move(other.base);
return *this;
}
private:
std::unique_ptr<T> base;
};
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;
}
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.
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;
};
I'm trying to create an Object Reference template class that will hold class pointers and everything works except when trying to type cast base class ptr to a derived class ptr.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define null nullptr
class BaseType;
class DerivedType;
template<class T>
class ObjRef {
public:
T *ptr = null; //should be private
ObjRef& operator= (T *ptr) { this->ptr = ptr; return *this; }
ObjRef& operator= (const ObjRef &ref) { ptr = ref.ptr; return *this; }
operator T*() const {return ptr;}
operator T() const {return *ptr;}
ObjRef() {}
ObjRef(const ObjRef ©) { ptr = copy.ptr; }
#ifdef VOID_FIX
ObjRef(void*p) { ptr = (T*)p; } //this could fix the bug except would not work with multiple inheritance and is not safe
#else
ObjRef(T*p) { ptr = p; }
#endif
~ObjRef() { }
T* operator->() const {return ptr;} //unfortunately operation. (dot) can not be overloaded - that would make life too easy :(
};
class Object {};
class BaseType : public Object {
public:
int baseValue;
};
class DerivedType : public BaseType {
public:
operator BaseType*() {return (BaseType*)this;} //helpful?
int derivedValue;
};
typedef ObjRef<BaseType> Base;
typedef ObjRef<DerivedType> Derived;
void func4(Base x) {
x->baseValue = 1;
}
void func5(Derived x) {
x->derivedValue = 1;
}
int main() {
Base b = null;
Derived d = null;
Base x;
x = d; //no type cast needed
func4((Base)d); //cast from Derived to Base class - no problem
b = d; //base does point to derived
// func5((Derived)b); //cast from Base to Derived - does not work (desired syntax)
// with gcc -fpermissive can be used to change error to warning - can I silence the warning ?
// what would cl.exe equivalent be?
// func5((Derived)b.ptr); //invalid cast, ptr should be private
// func5((DerivedType*)b); //invalid cast, ptr should be private
// func5(dynamic_cast<DerivedType*>(b.ptr)); //invalid cast, source type is not polymorphic, ptr should be private
func5((DerivedType*)b.ptr); //this works but is undesired and ptr should be private
func5(static_cast<DerivedType*>(b.ptr)); //works but again is undesired and ptr should be private
return 0;
}
In the example ObjRef<> is a template that holds a pointer to the class defined and is used as a new type. It works fine except for trying to cast base class to derived class. Look at how func5() is being called with a base class reference. The first attempt is the desired syntax. If I use the ptr inside the reference class it will work but that is undesired.
I just feel like I'm missing an operator or something.
Thanks.
As usual I found the solution just moments after posting.
The ObjRef<> class needs to know the base class.
Here is the new code:
#include <stdio.h>
#include <stdlib.h>
#define null nullptr
class BaseType;
class DerivedType;
template<class T>
class ObjRef {
public:
T *ptr = null;
ObjRef& operator= (auto *ptr) { this->ptr = ptr; return *this; }
ObjRef& operator= (const ObjRef<auto> &ref) { ptr = ref.ptr; return *this; }
operator T*() const {return ptr;}
ObjRef() {}
ObjRef(const ObjRef<auto> ©) { ptr = (T*)copy.ptr; }
ObjRef(T*p) { ptr = p; }
~ObjRef() { }
T* operator->() const {return ptr;} //unfortunately operator. (dot) can not be overloaded - that would make life too easy :(
};
class Object {};
class BaseType : public virtual Object {
public:
int baseValue;
};
class InterfaceType : public virtual Object {
public:
virtual void func7() {
printf("it works!\n");
};
};
typedef ObjRef<InterfaceType> Interface;
class DerivedType : public BaseType, public InterfaceType {
public:
int derivedValue;
};
typedef ObjRef<BaseType> Base;
typedef ObjRef<DerivedType> Derived;
void func4(Base x) {
x->baseValue = 1;
}
void func5(Derived x) {
x->derivedValue = 2;
}
void func6(Interface x) {
x->func7();
}
int main() {
Base b = new BaseType();
Derived d = new DerivedType();
Base x;
x = d; //no type cast needed
func4((Base)d); //cast from Derived to Base class - no problem
printf("BaseValue=%d\n", d->baseValue);
b = d; //base does point to derived
func5((Derived)b); //cast from Base to Derived - works now!
printf("DerivedValue=%d\n", d->derivedValue);
func6(d);
return 0;
}
UPDATE : Posted a new version that will work with any level of inheritance but now requires C++14 (auto keyword)
UPDATE #2 : Now uses a single ObjRef class (still requires C++14). Unfortunately cl.exe doesn't support 'auto' template parameters yet :(
UPDATE #3 : Added some test code to prove it works.
suppose I have those 2 classes:
class num{
public:
int a;
num(){};
num(int x):a(x){};
num(const num& n):a(n.a){}
virtual bool operator==(const num& n)const = 0;
virtual ~num(){};
};
class tmp: public num{
public:
tmp(){};
tmp(int x):num(x){};
tmp(const num& n): num(n){}
tmp(const tmp& t): num(t.a){}
virtual bool operator==(const num& n)const{
return tmp(n).a == a;
}
virtual ~tmp(){};
};
and something like this in main:
int main() {
num* x = &get(...);
return 0;
}
get return a reference of type tmp (in this case. in general it returns reference to a type that inherits from num)
what I want to do is create another num* y that will point to a copy of *x so that if I change *y I won't change *x. and I can't quite figure out how to do this since num is abstract so I can't create an object of this type to make a copy.
ok and another question.
if I overload << operator:
std::ostream& operator<<(std::ostream& os, const tmp& t){
return os<<t.a<<endl;
}
and then try to do this:
cout<<*x<<endl;
I get an error no match for 'operator<<'
why is that?
You're looking for the prototype pattern, also often called clone pattern.
It's basically a pure virtual method
virtual std::unique_ptr<num> clone() const = 0;
... that you declare in num, to be overriden by each derived class. You then just call x->clone(); to get a brand new object of the correct type.
You'll need a virtual function to clone an object based on its dynamic type. It will have to return a (preferably smart) pointer to a newly allocated object of the correct type. For example:
class num {
public:
virtual std::unique_ptr<num> clone() const = 0;
// other members...
};
class my_num : public num {
public:
virtual std::unique_ptr<num> clone() const {
return std::make_unique<my_num>(*this);
}
// other members...
};
int main() {
num* x = &get(...);
auto y = x->clone();
}