I am trying to implement virtual class with pure virtual method and 'copy and swap' idiom, but I've encountered some problems. Code won't compile because I am creating instance in the assign operator of the class A which contains pure virtual method.
Is there a way how to use pure virtual method and copy and swap idiom?
class A
{
public:
A( string name) :
m_name(name) { m_type = ""; }
A( const A & rec) :
m_name(rec.m_name), m_type(rec.m_type) {}
friend void swap(A & lhs, A & rhs)
{
std::swap(lhs.m_name, rhs.m_name);
std::swap(lhs.m_type, rhs.m_type);
}
A & operator=( const A & rhs)
{
A tmp(rhs);
swap(*this, tmp);
return *this;
}
friend ostream & operator<<( ostream & os,A & x)
{
x.print(os);
return os;
}
protected:
virtual void print(ostream & os) =0;
string m_type;
string m_name;
};
class B : A
{
public:
B(string name, int att) :
A(name),
m_att(att)
{
m_type="B";
}
B( const B & rec) :
A(rec),
m_att(rec.m_att) {}
friend void swap(B & lhs, B & rhs)
{
std::swap(lhs.m_att, rhs.m_att);
}
B & operator=( const B & rec)
{
B tmp(rec) ;
swap(*this, tmp);
return *this;
}
private:
virtual void print(ostream & os);
int m_att;
};
Error message:
In member function ‘A& A::operator=(const A&)’:|
error: cannot declare variable ‘tmp’ to be of abstract type ‘A’|
because the following virtual functions are pure within ‘A’:|
virtual void A::print(std::ostream&)|
As your compiler informs you, you cannot create a variable of abstract type. There is no way of dancing around that.
This leaves you three main options:
Stop using pure virtual functions
First, you could just get rid of the pure virtual methods and provide a little stub in each of them that calls std::terminate, which would obviously break compile time detection of whether all (former) pure virtual methods are overridden in all derived classes.
This will cause slicing, since it will only copy the base class and everything that makes out the derived class is lost.
Use a stub class w/o pure virtual functions
Similar to that, you could create a derived class that implements all virtual methods with simple stubs (possibly calling std::terminate), and is used only used as a "instantiatable version of the base class".
The most important part to implement for this class would be a constructor that takes a const reference to the base class, so you can just use it instead of copying the base class. This example also adds a move constructor, because I am a performance fetishist.
This causes the same slicing problem as the first option. This may be your intended result, based on what you are doing.
struct InstantiatableA : public A {
InstantiatableA(A const& rhs) : A(rhs) { }
InstantiatableA(A&& rhs) : A(::std::move(rhs)) { }
void print(ostream&) override { ::std::terminate(); }
};
A& A::operator=(InstantiatableA rhs) {
using ::std::swap;
swap(*this, rhs);
return *this;
}
Note: This is really a variable of type A, although I said it could not be done. The only thing you have to be aware is that the variable of type A lives inside a variable of type InstantiatableA!
Use a copy factory
Finally, you can add a virtual A* copy() = 0; to the base class. Your derived class B will then have to implement it as A* copy() override { return new B(*this); }. The reason dynamic memory is necessary is because your derived types may require arbitrarily more memory than your base class.
You're just facing the fact that inheritance works awkwardly with copy semantics.
For instance, imagine you found a trick to pass the compiling phase, what would mean (following example uses assignment but the issue is the same with a copy) :
// class A
// a class B : public A
// another class C : public A inheriting publicly from A
// another class D : public B inheriting publicly from B
B b1;
C c1;
D d1;
// Which semantic for following valid construction when copy/assignment is defined in A ?
b1 = c1;
b1 = d1;
A &ra = b1;
B b2;
// Which semantic for following valid construction when copy/assignment is defined in A ?
ra = b2;
ra = c1;
ra = d1;
CRTP is a choice:
template<typename swappable>
struct copy_swap_crtp{
auto& operator=(copy_swap_crtp const& rhs){
if (this==std::addressof(tmp))
return *this;
swappable tmp{rhs.self()};
self().swap(tmp);
return *this;
};
auto& operator=(copy_swap_crtp && rhs){
self().swap(rhs.self());
return *this;
};
protected:
auto& self(){return *static_cast<swappable*>(this);};
//auto& self()const{return *static_cast<swappable const*>(this);};
};
user class:
struct copy_swap_class
: copy_swap_crtp<copy_swap_class>
{
copy_swap_class(copy_swap_class const&);
void swap(copy_swap_class&);
};
cheers,
FM.
The compiler is right. The class A is abstract class, therefore you can not create instances of it in the operator=.
In B, you just declared the print function, but you didn't implement it. Meaning, you will get linking errors.
By implementing it, it compiles fine (if we ignore various warnings) :
void B::print(ostream & os )
{
os << m_att;
}
by the way :
B inherits privately from A, is that what you wanted?
order of initialization in A's copy constructor is wrong
you initialized m_type in A's constructor's body and not in the initialization list
Related
I have a class B with a set of constructors and an assignment operator.
Here it is:
class B
{
public:
B();
B(const string& s);
B(const B& b) { (*this) = b; }
B& operator=(const B & b);
private:
virtual void foo();
// and other private member variables and functions
};
I want to create an inheriting class D that will just override the function foo(), and no other change is required.
But, I want D to have the same set of constructors, including copy constructor and assignment operator as B:
D(const D& d) { (*this) = d; }
D& operator=(const D& d);
Do I have to rewrite all of them in D, or is there a way to use B's constructors and operator? I would especially want to avoid rewriting the assignment operator because it has to access all of B's private member variables.
You can explicitly call constructors and assignment operators:
class Base {
//...
public:
Base(const Base&) { /*...*/ }
Base& operator=(const Base&) { /*...*/ }
};
class Derived : public Base
{
int additional_;
public:
Derived(const Derived& d)
: Base(d) // dispatch to base copy constructor
, additional_(d.additional_)
{
}
Derived& operator=(const Derived& d)
{
Base::operator=(d);
additional_ = d.additional_;
return *this;
}
};
The interesting thing is that this works even if you didn't explicitly define these functions (it then uses the compiler generated functions).
class ImplicitBase {
int value_;
// No operator=() defined
};
class Derived : public ImplicitBase {
const char* name_;
public:
Derived& operator=(const Derived& d)
{
ImplicitBase::operator=(d); // Call compiler generated operator=
name_ = strdup(d.name_);
return *this;
}
};
Short Answer: Yes you will need to repeat the work in D
Long answer:
If your derived class 'D' contains no new member variables then the default versions (generated by the compiler should work just fine). The default Copy constructor will call the parent copy constructor and the default assignment operator will call the parent assignment operator.
But if your class 'D' contains resources then you will need to do some work.
I find your copy constructor a bit strange:
B(const B& b){(*this) = b;}
D(const D& d){(*this) = d;}
Normally copy constructors chain so that they are copy constructed from the base up. Here because you are calling the assignment operator the copy constructor must call the default constructor to default initialize the object from the bottom up first. Then you go down again using the assignment operator. This seems rather inefficient.
Now if you do an assignment you are copying from the bottom up (or top down) but it seems hard for you to do that and provide a strong exception guarantee. If at any point a resource fails to copy and you throw an exception the object will be in an indeterminate state (which is a bad thing).
Normally I have seen it done the other way around.
The assignment operator is defined in terms of the copy constructor and swap. This is because it makes it easier to provide the strong exception guarantee. I don't think you will be able to provide the strong guarantee by doing it this way around (I could be wrong).
class X
{
// If your class has no resources then use the default version.
// Dynamically allocated memory is a resource.
// If any members have a constructor that throws then you will need to
// write your owen version of these to make it exception safe.
X(X const& copy)
// Do most of the work here in the initializer list
{ /* Do some Work Here */}
X& operator=(X const& copy)
{
X tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(X& s) throws()
{
/* Swap all members */
}
};
Even if you derive a class D from from X this does not affect this pattern.
Admittedly you need to repeat a bit of the work by making explicit calls into the base class, but this is relatively trivial.
class D: public X
{
// Note:
// If D contains no members and only a new version of foo()
// Then the default version of these will work fine.
D(D const& copy)
:X(copy) // Chain X's copy constructor
// Do most of D's work here in the initializer list
{ /* More here */}
D& operator=(D const& copy)
{
D tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(D& s) throws()
{
X::swap(s); // swap the base class members
/* Swap all D members */
}
};
You most likely have a flaw in your design (hint: slicing, entity semantics vs value semantics). Having a full copy/value semantics on an object from a polymorphic hierarchy is often not a need at all. If you want to provide it just in case one may need it later, it means you'll never need it. Make the base class non copyable instead (by inheriting from boost::noncopyable for instance), and that's all.
The only correct solutions when such need really appears are the envelop-letter idiom, or the little framework from the article on Regular Objects by Sean Parent and Alexander Stepanov IIRC. All the other solutions will give you trouble with slicing, and/or the LSP.
On the subject, see also C++CoreReference C.67: C.67: A base class should suppress copying, and provide a virtual clone instead if "copying" is desired.
You will have to redefine all constructors that are not default or copy constructors. You do not need to redefine the copy constructor nor assignment operator as those provided by the compiler (according to the standard) will call all the base's versions:
struct base
{
base() { std::cout << "base()" << std::endl; }
base( base const & ) { std::cout << "base(base const &)" << std::endl; }
base& operator=( base const & ) { std::cout << "base::=" << std::endl; }
};
struct derived : public base
{
// compiler will generate:
// derived() : base() {}
// derived( derived const & d ) : base( d ) {}
// derived& operator=( derived const & rhs ) {
// base::operator=( rhs );
// return *this;
// }
};
int main()
{
derived d1; // will printout base()
derived d2 = d1; // will printout base(base const &)
d2 = d1; // will printout base::=
}
Note that, as sbi noted, if you define any constructor the compiler will not generate the default constructor for you and that includes the copy constructor.
The original code is wrong:
class B
{
public:
B(const B& b){(*this) = b;} // copy constructor in function of the copy assignment
B& operator= (const B& b); // copy assignment
private:
// private member variables and functions
};
In general, you can not define the copy constructor in terms of the copy assignment, because the copy assignment must release the resources and the copy constructor don't !!!
To understand this, consider:
class B
{
public:
B(Other& ot) : ot_p(new Other(ot)) {}
B(const B& b) {ot_p = new Other(*b.ot_p);}
B& operator= (const B& b);
private:
Other* ot_p;
};
To avoid memory leak , the copy assignment first MUST delete the memory pointed by ot_p:
B::B& operator= (const B& b)
{
delete(ot_p); // <-- This line is the difference between copy constructor and assignment.
ot_p = new Other(*b.ot_p);
}
void f(Other& ot, B& b)
{
B b1(ot); // Here b1 is constructed requesting memory with new
b1 = b; // The internal memory used in b1.op_t MUST be deleted first !!!
}
So, copy constructor and copy assignment are different because the former construct and object into an initialized memory and, the later, MUST first release the existing memory before constructing the new object.
If you do what is originally suggested in this article:
B(const B& b){(*this) = b;} // copy constructor
you will be deleting an unexisting memory.
I run into MISRA C++ 2008 Guidelines, and a rule 12-8-2 in this guideline says:
The copy assignment operator shall be declared protected or private in an abstract class.
and then I thought, when I make an abstract class's assignment operator public,
Is it possible to call it from another class except its subclass?
I think it's impossible.
If this is true, why they define this rule?
Basically, from the point of view of class design, I don't use abstract class which has private member, and I don't define assignment operator in a base class. So, usually, there is no need to apply this rule. However, If there is an abstract base class's public assignment operator, I would make it protected (or private if possible), because it makes no sense to be public. Do you know any other good reasons to apply this rule?
Did I overlook anything?
If they consider a class with virtual function (not pure) an abstract, then most likely to prevent slicing. Normal terminology for it is base class.
#include <iostream>
struct A
{
virtual ~A(){}
virtual void foo(){ std::cout<<1<<std::endl; };
};
struct B : A
{
virtual void foo(){ std::cout<<2<<std::endl; };
};
int main()
{
B b;
A a = b; // ops, wrong output because of slicing
}
However, if your class is really abstract (meaning it has pure virtual methods), then the rule makes no sense.
struct A
{
virtual ~A(){}
virtual void foo() = 0;
};
struct B : A
{
virtual void foo(){}
};
int main()
{
B b;
A a = b; // compilation error
}
I don't define assignment operator in a base class.
It doesn't matter whether you define the assignment operator or not. If you do not do it, the compiler will generate one for you.
Abstract class are the classes whose implementation is unknown but you know how they will behave or interact with other classes. Hence it is unlikely that you know size or other details about abstract class which is actually needed in copy and assignment operators.
Also main problem comes with something earlier answers to this post talks about "Slicing problem" which becomes more problematic in polymorphic classes as assignment operator is not by default virtual.
Consider this
class A
{
};
class B : public A
{
}
int main()
{
B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
}
Now in above case a_ref is initialised to b2 object but in next line when it is assigned to b1 it will be A's operator= is called rather than B's operator= which might change other object b2. You can imagine situation where in class A and B are not empty.
Hence it is rule that you either make copy constructor and assignment operator as private not public and in case you make assignment operator public in Abstract class then make it virtual and in every derived implementation check compatibility using dynamic_cast.
By definition, abstract classes cannot be instantiated (e.g. see here). A class that cannot be instantiated cannot be copied. Therefore the rule is absurd.
I confirmed slicing problem pointed out by #BЈовић and #NIRAJ RATHI,
then I noticed a case that It's possible to call public assignment operator in abstract base class by using reference. It's possible but possibly causing slicing problem. So making assignment operator virtual, overriding it in subclass and downcasting is needed.
#include <stdio.h>
class X {
public:
int x;
X(int inx): x(inx) {}
virtual void doSomething() = 0;
virtual void print() { printf("X(%d)\n",x); }
virtual X& operator=(const X& rhs) {
printf("X& X::operator=() \n");
x = rhs.x;
return *this;
}
};
class Y : public X {
public:
int y;
Y(int inx,int iny) : X(inx), y(iny) {}
void doSomething() { printf("Hi, I'm Y."); }
virtual void print() { printf("Y(%d,%d)\n",x,y); }
virtual X& operator=(const X& rhs);
};
X& Y::operator=(const X& rhs) {
printf("X& Y::operator=() \n");
const Y& obj = dynamic_cast<const Y&>(rhs);
X::operator=(rhs);
y = obj.y;
return *this;
}
int main()
{
Y a(1,2);
Y a2(3,4);
X& r = a;
r = a2; // calling assignment operator on ABC without slicing!!
r.print();
}
In my conclusion:
- It's possible to call assignment operator in abstract base class by using reference.
- The rule 12-8-2 is intended to prevent slicing problem.
- If there is no slicing problem, I don't always have to apply the rule 12-8-2.
BЈовић: However, if your class is really abstract (meaning it has pure virtual methods), then the rule makes no sense.
It does, as the assignment operator could accidentaly be called on pointers/references to the base class, which would always lead to slicing.
class cA
{
public:
int x;
virtual ~cA() { }
virtual void f() = 0;
};
class cB: public cA
{
int y;
virtual void f() { }
};
cA * a = new cB, * b = new cB;
*a = *b; // slicing: x is copied, y is not
The rule does make sense for a couple of reasons:
prevent partial assignment
prevent copying between incompatible classes
Suppose we have an abstract base class Animal and a couple of derived classes, Lizard and Chicken:
class Animal {
public:
...
};
class Lizard: public Animal {
...
};
class Chicken: public Animal {
...
};
The assignment operator by default is public. Now consider this code:
Lizard liz1;
Lizard liz2;
Animal *pAnimal1 = &liz1;
Animal *pAnimal2 = &liz2;
...
*pAnimal1 = *pAnimal2;
The assignment operator invoked on the last line is that of the Animal class, even though the objects involved are of type Lizard. Therefore, only the Animal part of liz1 will be modified. This is a partial assignment. After the assignment, liz1's Animal members have the values they got from liz2, but liz1's Lizard members remain unchanged.
It also possible via Animal pointers to assign a Lizard to a Chicken. That doesn't make a lot of sense, since they are incompatible with each other, and we might want to prevent such a thing happening. The easiest way to prevent such assignments is to make operator= protected in Animal. That way, lizards can be assigned to lizards and chickens can be assigned to chickens, but partial and mixed-type assignments are forbidden:
class Animal {
protected:
Animal& operator=(const Animal& rhs);
...
};
Alternatively, the assignment operator can be defined =delete if copying is to be prohibited in this class hierarchy. Actually, assignment operators that are private or protected needn't return *this at all. They can return the type void.
Consider classic virtual inheritance diamond hierarchy. I wonder to know what is the right implementation of copy and swap idiom in such hierarchy.
The example is a little artificial - and it is not very smart - as it would play good with default copy semantic for A,B,D classes. But just to illustrate the problem - please forget about the example weaknesses and provide the solution.
So I have class D derived from 2 base classes (B<1>,B<2>) - each of B classes inherits virtually from A class. Each class has non trivial copy semantics with using of copy and swap idiom. The most derived D class has problem with using this idiom. When it calls B<1> and B<2> swap methods - it swaps virtual base class members twice - so A subobject remains unchanged!!!
A:
class A {
public:
A(const char* s) : s(s) {}
A(const A& o) : s(o.s) {}
A& operator = (A o)
{
swap(o);
return *this;
}
virtual ~A() {}
void swap(A& o)
{
s.swap(o.s);
}
friend std::ostream& operator << (std::ostream& os, const A& a) { return os << a.s; }
private:
S s;
};
B
template <int N>
class B : public virtual A {
public:
B(const char* sA, const char* s) : A(sA), s(s) {}
B(const B& o) : A(o), s(o.s) {}
B& operator = (B o)
{
swap(o);
return *this;
}
virtual ~B() {}
void swap(B& o)
{
A::swap(o);
s.swap(o.s);
}
friend std::ostream& operator << (std::ostream& os, const B& b)
{ return os << (const A&)b << ',' << b.s; }
private:
S s;
};
D:
class D : public B<1>, public B<2> {
public:
D(const char* sA, const char* sB1, const char* sB2, const char* s)
: A(sA), B<1>(sA, sB1), B<2>(sA, sB2), s(s)
{}
D(const D& o) : A(o), B<1>(o), B<2>(o), s(o.s) {}
D& operator = (D o)
{
swap(o);
return *this;
}
virtual ~D() {}
void swap(D& o)
{
B<1>::swap(o); // calls A::swap(o); A::s changed to o.s
B<2>::swap(o); // calls A::swap(o); A::s returned to original value...
s.swap(o.s);
}
friend std::ostream& operator << (std::ostream& os, const D& d)
{
// prints A::s twice...
return os
<< (const B<1>&)d << ','
<< (const B<2>&)d << ','
<< d.s;
}
private:
S s;
};
S is just a class storing string.
When doing copy you will see A::s remains unchanged:
int main() {
D x("ax", "b1x", "b2x", "x");
D y("ay", "b1y", "b2y", "y");
std::cout << x << "\n" << y << "\n";
x = y;
std::cout << x << "\n" << y << "\n";
}
And the result is:
ax,b1x,ax,b2x,x
ay,b1y,ay,b2y,y
ax,b1y,ax,b2y,y
ay,b1y,ay,b2y,y
Probably adding B<N>::swapOnlyMewould resolve the problem:
void B<N>::swapOnlyMe(B<N>& b) { std::swap(s, b.s); }
void D::swap(D& d) { A::swap(d); B<1>::swapOnlyMe((B<1>&)d); B<2>::swapOnlyMe((B<2>&)d); ... }
But what when B inherits privately from A?
Here's a philosophical rant:
I don't think virtual inheritance can or should be private. The entire point of a virtual base is that the most derived class owns the virtual base, and not the intermediate classes. Thus no intermediate class should be permitted to "hog" the virtual base.
Let me repeat the point: The most derived class owns the virtual base. This is evident in constructor initializers:
D::D() : A(), B(), C() { }
// ^^^^
// D calls the virtual base constructor!
In the same sense, all other operations in D should be immediately responsible for A. Thus we are naturally led to writing the derived swap function like this:
void D::swap(D & rhs)
{
A::swap(rhs); // D calls this directly!
B::swap(rhs);
C::swap(rhs);
// swap members
}
Putting all this together, we're left with only one possible conclusion: You have to write the swap functions of the intermediate classes without swapping the base:
void B::swap(B & rhs)
{
// swap members only!
}
void C::swap(C & rhs)
{
// swap members only!
}
Now you ask, "what if someone else wants to derive from D? Now we see the reason for Scott Meyer's advice to always make non-leaf classes abstract: Following that advice, you only implement the final swap function which calls the virtual base swap in the concrete, leaf classes.
Update: Here's something only tangentially related: Virtual swapping. We continue to assume that all non-leaf classes are abstract. First off, we put the following "virtual swap function" into every base class (virtual or not):
struct A
{
virtual void vswap(A &) = 0;
// ...
};
Usage of this function is of course reserved only to identical types. This is safeguarded by an implicit exception:
struct D : /* inherit */
{
virtual void vswap(A & rhs) { swap(dynamic_cast<D &>(rhs)); }
// rest as before
};
The overall utility of this is limited, but it does allow us swap to objects polymorphically if we happen to know that they're the same:
std::unique_ptr<A> p1 = make_unique<D>(), p2 = make_unique<D>();
p1->vswap(*p2);
Virtual base generally means that most derived class of object is in control of it.
First solution: Reorganize your classes to be more fit for polymorphism. Make copy construction protected. Remove assignment and swap(). Add virtual clone(). Idea is that the classes should be treated as polymorphic. So they should be used with pointer or smart pointer. Swapped or assigned should be the pointer values, not the object values. In such context swap and assignment only confuse.
Second solution: Make B and C abstract and their pointers not to manage object lifetime. Destructors of B and C should be protected and non-virtual. B and C will not therefore be most derived classes of object. Make B::swap() and C::swap() protected and not swap the A subobject, may rename or add comment that it is business of inherited classes now. That removes lot of object slicing possibilities. Make D::swap() to swap A subobject. You get one swap of A.
Third solution: Make D::swap() to swap A subobject. That way the A subobject will be swapped 3 times and lands in correct place. Inefficient? The whole construct is probably bad idea anyway. I am for example not sure how well the virtual destructors and swaps cooperate here and lot of ways to slice objects are public here. It all seems similar to attempt of making virtual assignment operators that is bad idea in C++.
If something inherits from D on its order then it should make sure by swapping or not swapping A subobject that the count of swapping A is odd. It becomes to control so should take over and fix.
The private virtual idiom is one of ways to make a class final in C++. Nothing should be able to inherit from it. Interesting that you asked. If you ever use it, be sure to comment, it confuses most of the readers of code.
I would like to define an abstract base class X and enforce the following:
a) every concrete class Y that inherits from X define a constructor Y(int x)
b) it should be possible to test whether two Y objects are equal.
For a, one not very good solution is to put a pure virtual fromInt method in X
which concrete class will have to define. But I cannot enforce construction.
For b), I cannot seem to use a pure virtual method in X
bool operator == (const X& other) const =0;
because in overridden classes this remains undefined. It is not enough to define
bool operator == (const Y& other) const { //stuff}
because the types don't match. How do I solve these problems?
You can force construction by making the no argument constructor private and having a public single int argument constructor in your base class. As long as the base class has some pure virtual methods, then your subclasses must call that constructor.
As for the operator==, try defining
bool operator == (const BaseClass& other) const { .. };
in all of your subclasses. Worst case, you can define a public equals(const BaseClass& other) method that is pure virtual in your base.
EDIT: the forcing constructor thing is not entirely true. What I suggested forces sub classes to call the single argument constructor. They could have a no argument constructor that passes a constant up to the base in constructor.
There's an easy solution.
// Class X
// (... some documentation ...)
//
// ** NOTE: All subclasses of X must have a constructor that takes a single int,
// ** and overload operator==.
class X {
...
For b), you can define virtual bool operator == (const X & other) const = 0 in X.
You can't have const Y & other as the parameter in the comparison, but Ys will be automatically casted to Xs and then you can use dynamic_cast to see if it's a class that you can compare with.
a - should be possible if you use CRTP and an intermediary, friend, templated subclass that all user code must inherit from. Something like so:
struct X
{
virtual bool compare(X const&) const = 0;
private:
X();
template < typename T >
friend struct client_base; // don't recall the correct code here.
};
template < typename Sub >
struct client_base : X
{
// use boost::concepts to verify Sub has Sub(int)
Sub() : X() {}
};
struct Y : client_base<Y>
{
Y(int);
bool compare(X const& x)
{
if ((Y* other = dynamic_cast<Y*>(x)) && *other == *this) return true;
return false;
}
};
Obviously I've left a lot for you to figure out to make this a complete solution.
a) doesn't have a sense as for me but you can create something
template< typename T >
Base* create( int x )
{
return T::create( x );
}
for b) ask google about "multi methods" implementation in c++
Enforcing to be constructible from an integer does not make any sense: each derived class is free to define its constructors as it wishes. You can however enforce them to pass an integer to the base class... not that it makes much more sense anyway.
The operator== is also contorted, you can however get the essence of it:
class Base
{
public:
bool operator==(const Base& rhs) const;
bool operator!=(const Base& rhs) const { return !(*this == rhs); }
private:
virtual bool equals(const Base& rhs) const = 0; // will pass only objects
// of the same dynamic type
};
bool Base::operator==(const Base& rhs) const
{
return typeid(*this) == typeid(rhs) && this->equals(rhs);
}
bool Derived::equals(const Base& rhs) const // We KNOW Base is actually a Derived
{
return *this == static_cast<const Derived&>(rhs);
}
You could try and prettify it a bit by using templates and CRTP, but what if Derived was inherited from ? it would not hold.
I have a class B with a set of constructors and an assignment operator.
Here it is:
class B
{
public:
B();
B(const string& s);
B(const B& b) { (*this) = b; }
B& operator=(const B & b);
private:
virtual void foo();
// and other private member variables and functions
};
I want to create an inheriting class D that will just override the function foo(), and no other change is required.
But, I want D to have the same set of constructors, including copy constructor and assignment operator as B:
D(const D& d) { (*this) = d; }
D& operator=(const D& d);
Do I have to rewrite all of them in D, or is there a way to use B's constructors and operator? I would especially want to avoid rewriting the assignment operator because it has to access all of B's private member variables.
You can explicitly call constructors and assignment operators:
class Base {
//...
public:
Base(const Base&) { /*...*/ }
Base& operator=(const Base&) { /*...*/ }
};
class Derived : public Base
{
int additional_;
public:
Derived(const Derived& d)
: Base(d) // dispatch to base copy constructor
, additional_(d.additional_)
{
}
Derived& operator=(const Derived& d)
{
Base::operator=(d);
additional_ = d.additional_;
return *this;
}
};
The interesting thing is that this works even if you didn't explicitly define these functions (it then uses the compiler generated functions).
class ImplicitBase {
int value_;
// No operator=() defined
};
class Derived : public ImplicitBase {
const char* name_;
public:
Derived& operator=(const Derived& d)
{
ImplicitBase::operator=(d); // Call compiler generated operator=
name_ = strdup(d.name_);
return *this;
}
};
Short Answer: Yes you will need to repeat the work in D
Long answer:
If your derived class 'D' contains no new member variables then the default versions (generated by the compiler should work just fine). The default Copy constructor will call the parent copy constructor and the default assignment operator will call the parent assignment operator.
But if your class 'D' contains resources then you will need to do some work.
I find your copy constructor a bit strange:
B(const B& b){(*this) = b;}
D(const D& d){(*this) = d;}
Normally copy constructors chain so that they are copy constructed from the base up. Here because you are calling the assignment operator the copy constructor must call the default constructor to default initialize the object from the bottom up first. Then you go down again using the assignment operator. This seems rather inefficient.
Now if you do an assignment you are copying from the bottom up (or top down) but it seems hard for you to do that and provide a strong exception guarantee. If at any point a resource fails to copy and you throw an exception the object will be in an indeterminate state (which is a bad thing).
Normally I have seen it done the other way around.
The assignment operator is defined in terms of the copy constructor and swap. This is because it makes it easier to provide the strong exception guarantee. I don't think you will be able to provide the strong guarantee by doing it this way around (I could be wrong).
class X
{
// If your class has no resources then use the default version.
// Dynamically allocated memory is a resource.
// If any members have a constructor that throws then you will need to
// write your owen version of these to make it exception safe.
X(X const& copy)
// Do most of the work here in the initializer list
{ /* Do some Work Here */}
X& operator=(X const& copy)
{
X tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(X& s) throws()
{
/* Swap all members */
}
};
Even if you derive a class D from from X this does not affect this pattern.
Admittedly you need to repeat a bit of the work by making explicit calls into the base class, but this is relatively trivial.
class D: public X
{
// Note:
// If D contains no members and only a new version of foo()
// Then the default version of these will work fine.
D(D const& copy)
:X(copy) // Chain X's copy constructor
// Do most of D's work here in the initializer list
{ /* More here */}
D& operator=(D const& copy)
{
D tmp(copy); // All resource all allocation happens here.
// If this fails the copy will throw an exception
// and 'this' object is unaffected by the exception.
swap(tmp);
return *this;
}
// swap is usually trivial to implement
// and you should easily be able to provide the no-throw guarantee.
void swap(D& s) throws()
{
X::swap(s); // swap the base class members
/* Swap all D members */
}
};
You most likely have a flaw in your design (hint: slicing, entity semantics vs value semantics). Having a full copy/value semantics on an object from a polymorphic hierarchy is often not a need at all. If you want to provide it just in case one may need it later, it means you'll never need it. Make the base class non copyable instead (by inheriting from boost::noncopyable for instance), and that's all.
The only correct solutions when such need really appears are the envelop-letter idiom, or the little framework from the article on Regular Objects by Sean Parent and Alexander Stepanov IIRC. All the other solutions will give you trouble with slicing, and/or the LSP.
On the subject, see also C++CoreReference C.67: C.67: A base class should suppress copying, and provide a virtual clone instead if "copying" is desired.
You will have to redefine all constructors that are not default or copy constructors. You do not need to redefine the copy constructor nor assignment operator as those provided by the compiler (according to the standard) will call all the base's versions:
struct base
{
base() { std::cout << "base()" << std::endl; }
base( base const & ) { std::cout << "base(base const &)" << std::endl; }
base& operator=( base const & ) { std::cout << "base::=" << std::endl; }
};
struct derived : public base
{
// compiler will generate:
// derived() : base() {}
// derived( derived const & d ) : base( d ) {}
// derived& operator=( derived const & rhs ) {
// base::operator=( rhs );
// return *this;
// }
};
int main()
{
derived d1; // will printout base()
derived d2 = d1; // will printout base(base const &)
d2 = d1; // will printout base::=
}
Note that, as sbi noted, if you define any constructor the compiler will not generate the default constructor for you and that includes the copy constructor.
The original code is wrong:
class B
{
public:
B(const B& b){(*this) = b;} // copy constructor in function of the copy assignment
B& operator= (const B& b); // copy assignment
private:
// private member variables and functions
};
In general, you can not define the copy constructor in terms of the copy assignment, because the copy assignment must release the resources and the copy constructor don't !!!
To understand this, consider:
class B
{
public:
B(Other& ot) : ot_p(new Other(ot)) {}
B(const B& b) {ot_p = new Other(*b.ot_p);}
B& operator= (const B& b);
private:
Other* ot_p;
};
To avoid memory leak , the copy assignment first MUST delete the memory pointed by ot_p:
B::B& operator= (const B& b)
{
delete(ot_p); // <-- This line is the difference between copy constructor and assignment.
ot_p = new Other(*b.ot_p);
}
void f(Other& ot, B& b)
{
B b1(ot); // Here b1 is constructed requesting memory with new
b1 = b; // The internal memory used in b1.op_t MUST be deleted first !!!
}
So, copy constructor and copy assignment are different because the former construct and object into an initialized memory and, the later, MUST first release the existing memory before constructing the new object.
If you do what is originally suggested in this article:
B(const B& b){(*this) = b;} // copy constructor
you will be deleting an unexisting memory.