warning assignment operator class reference - c++

i have this code:
class ABC{
public:
ABC(std::ostream& os) : _os(os) {}
void operator() (const Stud* course) {
Stud->print(_os);
}
ABC& operator=(const ABC& other); //Declaration of operator=
private:
std::ostream& _os;
};
befor i define assignment operator i get warning "assignment operator could not be generated".
i want assignment between object this class do nothing, its just class print in for_each algorithm.
i try write :
ABC& operator=(const ABC& other){
return *this;
}
but still get warning the other not use.
how can i define assignment operator do nothing. (no Use the #pragma warning statement to suppress the warning).
thanks!

To get rid of the warning about an unused argument, just don't name it:
ABC& operator=(const ABC&){
return *this;
}
The reason that the compiler can't generate an assignment operator for your class is that it has a reference variable, and these can only be initialised, never re-assigned.
If you don't need an assignment operator, but only added one to make the compiler happy, you can declare it private and then not provide an implementation.

Few problems in your code...
class ABC
{
public:
ABC(std::ostream& os) : _os(os) {}
void operator() (const Stud* course)
{
//Stud->print(_os); // you can't use Stud here - this is wrong
course->print(_os);
}
ABC& operator=(const ABC& other); //Declaration of operator=
private:
std::ostream& _os;
};
Additionally, as operator() defines course as const Stud* the print method in Stud class should be defined as const as well.
other than that, the code compiles perfercly.

Related

Regarding c++ operator assign behavior when have parent child relationship

I have a question about operator= that accepts parent reference type.
When there is a abstract class and it's implemented class,
why is not enough to have single operator= that accept parent reference type?
Below is my code
#include <iostream>
class AbstractType {
public:
virtual ~AbstractType() {}
virtual AbstractType& operator=(const AbstractType& other) {
std::cout << "AbstractType& operator=(const AbstractType&)" << std::endl;
return *this;
}
};
class Type1: public AbstractType {
public:
virtual ~Type1() {}
virtual Type1& operator=(const AbstractType& other) {
std::cout << "Type1& operator=(const AbstractType&)" <<
std::endl;
return *this;
}
/*
virtual Type1& operator=(const Type1& other) {
std::cout << "Type1& operator=(const Type1&)" << std::endl;
// Just redirecting here! What a waste!
return operator=(dynamic_cast<const AbstractType&>(other));
}
*/
};
int main()
{
Type1 t1;
AbstractType& r1 = t1;
Type1 t2;
AbstractType& r2 = t2;
// Type1& operator=(const AbstractType&). It's fine!
r1 = r2;
// AbstractType& operator=(const AbstractType&)!! Why??
// Expected `Type1& operator=(const AbstractType&)` to be called!
t1 = t2;
return 0;
}
You can find given parameter is being just redirected in Type1& operator=(const Type1&) that is ignored by comment.
Uncomment Type1& operator=(const Type1&) is just working for me,
but if say, I have more than a hundred of TypeX then I have to make two hundred of copy assignment which is I can't understand because it seems to me just having Type1& operator=(const AbstractType& other) is enough.
And most cases I only have AbstractType to handle things around.
Very rare to know it's specific type in advance under limited situations.
Anyone can suggest me better solution?
// AbstractType& operator=(const AbstractType&)!! Why??
// Expected `Type1& operator=(const AbstractType&)` to be called!
t1 = t2;
Here you are calling:
t1.operator=(t2);
Since t1 and t2 have Type1, the compiler will match the following function:
Type1 & Type1::operator=(const Type1 &);
which is the implicitly-defined copy assignment operator, and which will call the copy assignment operator of the base:
AbstractType & AbstractType::operator=(const AbstractType &);
However, this call is not dynamically dispatched -- which is the reason you end up seeing your results.
Uncomment Type1& operator=(const Type1&) is just working for me
Note that:
There is no need for dynamic_cast.
There is no need to make a virtual call.
The operator itself does not need to be virtual.
In other words, you can simplify to:
Type1& operator=(const Type1& other)
{
return Type1::operator=(static_cast<const AbstractType&>(other));
}
Because of Liskovs substitution principle, which states that if a program, module or function is using a Base class, then the reference of Base class can be replaced with Derived class without affecting programs functionality. So in your particular case, implementing it in terms of Curiously recurring template pattern will be an elegant solution. Please see link for more info!

avoiding duplication in the assignment operator of a derived class

Consider the assignment operators in classes Parent and Child, below.
#include <iostream>
class Parent
{
public:
Parent(){};
virtual ~Parent(){};
Parent& operator=(const Parent& other){mP = other.mP; return *this;};
void setP(double inP){mP = inP;};
double getP(){return mP;};
protected:
double mP;
};
class Child : public virtual Parent
{
public:
Child(){};
virtual ~Child(){};
Child& operator=(const Child& other)
{
mC = other.mC;
mP = other.mP;// this line
return *this;
};
void setC(double inC){mC = inC;};
double getC(){return mC;};
protected:
double mC;
};
Is here a way to avoid the duplicate line mP = other.mP;?
The reason I am asking is that as the number of bases get higher and the inheritance structure gets more complicated, it is easy to lose track of members.
EDIT
The reason I need to implement the operator= is that it needs to check some things before the assignments.
Just call the Parent operator:
Child& operator=(const Child& other)
{
mC = other.mC;
Parent::operator=(other);
return *this;
}
Or really, don't implement either operator since both are trivial!
The best way to avoid this issue is to remove both of your operator= functions.
The compiler-generated operator= applies operator= to each member variable and base class, which is just what you were trying to do anyway.
Re-implementing the wheel just makes your code harder to read and maintain -- and sometimes less efficient.
Child& operator=(const Child& other) {
mC = other.mC;
mP = other.mP;
}
you can invoke the assignment operator of the parent prior to the child specific assignment in this way:
Child& operator=(const Child& other)
{
Parent::operator=(other);
mC = other.mC;
return *this;
};

copy & swap in base and derived class

I recently read about copy & swap and am now trying to implement the ctors in a base and derived class. I have the four constructors in both my base and derived class, however I am unsure how to implement the assignment operator of the derived class.
explicit Base(int i) : m_i{i} {}
Base(const Base & other) : m_i{other.m_i}
Base(Base && other) : Base(0) { swap(*this, other); }
Base & operator=(Base other) { swap(*this, other); return *this; }
friend void swap(Base & a, Base & b) noexcept {
using std::swap;
swap(a.m_i, b.m_i);
}
explicit Derived(int j) : Base(42), m_j(j) {}
Derived(const Derived & other) : Derived(other.m_j) {}
Derived(Derived && other) : Derived(other.m_j) { swap(*this, other); }
Derived & operator=(Derived other) { /*???*/ }
friend void swap(Derived & a, Derived & b) noexcept {
using std::swap;
swap(a.m_j, b.m_j);
}
Consider using = default as much as possible. And if we are talking about public inheritance, you really need a virtual destructor as well.
Here is how your Base would look using the copy/swap style:
class Base
{
int m_i;
public:
virtual ~Base() = default;
Base(const Base& other) = default;
Base& operator=(Base other) noexcept
{
swap(*this, other);
return *this;
}
Base(Base&& other) noexcept
: Base(0)
{
swap(*this, other);
}
explicit Base(int i) noexcept
: m_i{i}
{}
friend void swap(Base& a, Base& b) noexcept
{
using std::swap;
swap(a.m_i, b.m_i);
}
};
The only difference from what you have is that I've added the virtual destructor, and used = default for the copy constructor.
Now for Derived:
class Derived
: public Base
{
int m_j;
public:
Derived(const Derived& other) = default;
Derived& operator=(Derived other) noexcept
{
swap(*this, other);
return *this;
}
Derived(Derived&& other) noexcept
: Derived(0)
{
swap(*this, other);
}
explicit Derived(int j) noexcept
: Base(42)
, m_j{j}
{}
friend void swap(Derived& a, Derived& b) noexcept
{
using std::swap;
swap(static_cast<Base&>(a), static_cast<Base&>(b));
swap(a.m_j, b.m_j);
}
};
I've let the compiler implicitly take care of the destructor since the compiler will implicitly give me a virtual one that does the right thing in this case.
Again I've explicitly defaulted the copy constructor. This corrects a bug in your version which neglects to copy Base.
The operator= looks just like the Base version.
The Derived move constructor does not need to move or copy anything from other since it is going to swap with other.
The Derived swap function must swap the Base part as well as the Derived part.
Now consider not using the copy/swap idiom. This can be surprisingly easier, and in some cases, higher performing.
For Base you can use = default for all 5 of your special members:
class Base
{
int m_i;
public:
virtual ~Base() = default;
Base(const Base&) = default;
Base& operator=(const Base&) = default;
Base(Base&&) = default;
Base& operator=(Base&&) = default;
explicit Base(int i) noexcept
: m_i{i}
{}
friend void swap(Base& a, Base& b) noexcept
{
using std::swap;
swap(a.m_i, b.m_i);
}
};
The only work that is really required here is your custom constructor and swap function.
Derived is even easier:
class Derived
: public Base
{
int m_j;
public:
explicit Derived(int j) noexcept
: Base(42)
, m_j{j}
{}
friend void swap(Derived& a, Derived& b) noexcept
{
using std::swap;
swap(static_cast<Base&>(a), static_cast<Base&>(b));
swap(a.m_j, b.m_j);
}
};
All 5 of the special members can be implicitly defaulted!
We couldn't default them in the Base because we needed to specify the virtual destructor, which inhibits the generation of the move members, and the generation of the copy members is deprecated with a user-declared destructor. But since we do not need to declare the destructor in Derived, we can just let the compiler handle everything.
As one of the big selling points of copy/swap is reduced coding, it can be ironic that using it can actually require more coding than letting the compiler default the special members.
Of course if the defaults do not do the right thing, then don't use them. I'm simply saying that the defaults should be your first choice, ahead of copy/swap.
You implement op= exactly the same way for Derived as for Base:
Derived& operator=(Derived other) { swap(*this, other); return *this; }
I hope you are aware of the up- and down-sides of passing the argument by value there, though:
Up-side: Only one function needed for all value categories.
Down-Side: Second move for xvalues, move in addition to the needed copy for prvalues.
Other points to consider:
Rule-of-thumb: Single-argument non-copy/move ctors should be explicit: You really don't want to have an implicit conversion from int to Base...
You forgot to re-implement swap for Derived (swap all sub-objects, both base and member). You might forego it if Derived does not add any members though.

How to make a C++ class produce non cloneable objects

How can I make a Class non-cloneable like we can do in Java while creating singleton.
Is there any condition we can put on copy constructor so that an exception can be thrown if user tries to make a copy of an object?
I am a novice in C++ so kindly add any info to this or redirect if an answer is already available for the same.
Just declare copy constructor and copy assign operator private
in C++03
class NonCopyable
{
public:
NonCopyable() { }
private:
NonCopyable(const NonCopyable&);
NonCopyable& operator=(const NonCopyable&);
};
Also you can make a class derive from NonCopyable, AnotherType is un-copyable
class AnotherNonCopyable : private NonCopyable
{
public:
AnotherNonCopyable () {}
}
With C++11:
class NonCopyableType
{
public:
NonCopyableType(const NonCopyableType&) = delete;
NonCopyableType& operator=(const NonCopyableType&) = delete;
};
You can delete the copy constructor and assignment operator:
struct Foo
{
Foo(const& Foo) = delete;
Foo& operator=(const Foo&) = delete;
};
If you don't have C++11 support, make them private, and don't implement them:
struct Foo
{
private:
Foo(const& Foo);
Foo& operator=(const Foo&);
};
Note In C++, class and struct are essentially the same.
Declare the copy-semantics as delete:
//C++11 only
MyClass(MyClass const &) = delete;
MyClass& operator=(MyClass const &) = delete;
That makes the class non-copyable!
//pre-C++11 code
private:
MyClass(MyClass const &); //declare only, don't define it
MyClass& operator=(MyClass const &); //declare only, don't define it
This should also work!
Is there any condition we can put on copy constructor so that an
exception can be thrown if user tries to make a copy of an object.
if you make the copy constructor private, The code will not compile when the programmer tries to make another copy. This is probably better than detecting the error with an exception at runtime.
class foo {
private:
operator = ( const foo& f);
};

Disallowing class copying in C++

When I want to disallow class copy in C++, I usually declare a private operator= and a copy constructor and I don't implement them:
class MyClass
{
char* _str;
int _len;
MyClass(const MyClass& rhs); //No implementation
MyClass& operator=(const MyClass& rhs); //No implementation
public:
MyClass();
MyClass(const char *);
}
Is this considered a bad style? Is there another way to do this?
In C++11 you can explicitly delete these functions (which is preferred over omitting the implementation, because it is more readable, and it will always generate a compiler-error, and not just a linker-error):
class MyClass
{
char* _str;
int _len;
MyClass(const MyClass& rhs) = delete;
MyClass& operator=(const MyClass& rhs) = delete;
public:
MyClass();
MyClass(const char *);
}
In C++03 you can use a base-class such as boost::noncopyable to achieve the same effect. This might be more readable (this is essentially the same approach as yours - this base-class has private copy-constructor and assignment-operator, so inheriting from it will make your class uncopyable):
class MyClass : boost::noncopyable
{
char* _str;
int _len;
public:
MyClass();
MyClass(const char *);
}
The difference between shallow and deep copying in C++ rests entirely in how you implement your copy-constructor (because your assignment operator should be implemented using your copy-constructor). If you don't have one, neither shallow nor deep copying is possible, if you have, it depends on how it is implemented.
You can create a preprocessor macro to achieve the same thing, e.g.
#define DISABLE_COPY_AND_ASSIGN(className) private: \
className(const className&); \
className& operator=(const className&);
and then use it like this:
class MyClass
{
DISABLE_COPY_AND_ASSIGN(MyClass)
public:
....
};
You can derive from boost::noncopyable as well:
class MyClass : boost::noncopyable
{
public:
....
};
Moreover, in C++11, you can use = delete:
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
There are two ways, and both would cause a compilation errors :
C++11 way:
class MyClass
{
char* _str;
int _len;
MyClass(const MyClass& rhs) = delete;
MyClass& operator=(const MyClass& rhs) = delete;
public:
MyClass();
MyClass(const char *);
};
C++03 way:
class MyClass
{
char* _str;
int _len;
public:
MyClass();
MyClass(const char *);
MyClass(const MyClass& rhs); //No implementation
MyClass& operator=(const MyClass& rhs); //No implementation
}
If you just declare copy constructors public, you'll get linker errors, but the compilation will pass. Since the compilation happens before linking, breaking the compilation is better, because you'll catch the errors sooner.