I have the following code:
#include <iostream>
using namespace std;
class Base {
public:
Base operator/(const Base& other){
Base res;
cout << "Base /" << endl;
return res;
}
Base& operator/=(const Base& other){
cout << "Base /=" << endl;
return *this;
}
};
class Derived : public Base {
public:
Derived operator/(const Derived& other){
Derived res;
cout << "Derived /" << endl;
return res;
}
};
int main() {
Derived d1, d2;
Base b1, b2;
b1 = d1 / d2;
b2 = d1 /= d2;
}
The second assignment outputs Base /=. Can I achieve that the second assignment to use the overridden operator/, without overriding operator/=? I think I have to implement one operator using the other.
This is a homework, so it is OK to give just the basic idea what to do.
Though being clearly not the preferred way and probably some sort of "ugly", it is possible to use Derived::operator/ without providing a Derived::operator/=. To do that, the following steps are necessary:
call operator / in the implementation of Base::operator/=
Make operator / virtual such that it is not statically bound in /=-implementation
Provide an operator/-implementation in class Derived that overrides the one in the Base, i.e. provide an operator virtual Base operator/(const Base&) in addition to Derived operator/(const Derived&) (note that the latter cannot override since it has a covariant argument type)
In this Derived::operator/(const Base& other)-implementation, check the dynamic type of other and explicitly call the respective implementation.
See the following code:
class Base {
public:
virtual Base operator/(const Base& other) const {
Base res;
cout << "Base /" << endl;
return res;
}
Base& operator/=(const Base& other){
cout << "Base /=" << endl;
*this = *this / other;
return *this;
}
};
class Derived : public Base {
public:
virtual Base operator/(const Base& other) const override {
cout << "Derived /(Base&)" << endl;
if(dynamic_cast<const Derived*>(&other)==0) {
// do something specific here, or call base operator:
return Base::operator/(other);
}
else {
return operator/(dynamic_cast<const Derived&>(other));
}
}
Derived operator/(const Derived& other) const { // cannot override
cout << "Derived /(Derived&)" << endl;
return *this;
}
};
int main() {
Derived d1, d2;
Base b1, b2;
b1 = d1 / d2;
// Output: Derived /(Derived&)
b2 = d1 /= d2;
// Output:
// Base /=
// Derived /(Base&)
// Derived /(Derived&)
return 0;
}
Be aware that an expression Derived d3 = d2 /= d1 is still not possible, because return type Base & of operator Base& Base::operator /= cannot be converted to Derived &.
Related
I was wondering how should I (or can I? does it make any sense?) overload the assignment operator when working with inheritance and upcasting?
Let's say we have Base class and Derived class (inherited from Base). If i have something like:
/// supose we have one overloaded assignment operator in Base like Base& operator=(const Base&) and
///one in Derived like Derived& operator=(const Derived&)...
Base* a, *b;
Derived c,d;
a = &c;
b = &d;
*a = *b /// this will call the function in Base
If that calls the Base function, why should I overload "=" again in Derived? Is overloading assignment operator in Derived necessary only for working directly with objects, not upcasting (pointers) ?
Here's some code that hopefully helps you out.
Derived Does Not Own A Dynamic Resource
The Base class holds a dynamic resource, so we are required to follow the Rule of 3 (should be 5, but kept it at 3 for brevity). I did so by utilizing the copy/swap idiom.
I then derive Derived from Base. It does not hold a dynamic resource, so I follow the Rule of 0 and don't provide a custom copy constructor, destructor, assignment operator, move constructor, or move assignment.
You can see from the output that the Base portion of the Derived objects are able to deep-copy themsleves just fine, and the Derived-only portion gets by just fine with shallow copy. The final output leaks memory, but I chose to do that to demonstrate an actual overwrite using a pointer to Base.
#include <iostream>
class Base {
private:
int* m = nullptr;
public:
Base() = default;
Base(int v) : m(new int(v)) {}
Base(const Base& other) : m(new int(*(other.m))) {}
virtual ~Base() {
delete m;
m = nullptr;
}
Base& operator=(Base other) {
swap(*this, other);
return *this;
}
friend void swap(Base& lhs, Base& rhs) {
using std::swap;
swap(lhs.m, rhs.m);
}
virtual void print() const {
std::cout << "Address: " << m << "\nValue: " << *m << '\n';
}
};
class Derived : public Base {
private:
double x = 0.0;
public:
Derived() = default;
Derived(double v) : Base(), x(v) {}
Derived(int i, double v) : Base(i), x(v) {}
void print() const override {
std::cout << "Address: " << &x << "\nValue: " << x << '\n';
Base::print();
}
};
int main() {
std::cout << "A\n";
Base* a = new Derived(5, 3.14);
a->print();
std::cout << "\nB\n";
Derived b = *(dynamic_cast<Derived*>(a)); // Copy ctor
b.print();
std::cout << "\nC\n";
Derived c;
c = b;
c.print();
std::cout << "\nReplace A (This leaks)\n";
a = new Derived(7, 9.81);
a->print();
}
Output:
A
Address: 0x21712d0
Value: 3.14
Address: 0x21712e0
Value: 5
B
Address: 0x7ffdd62964c8
Value: 3.14
Address: 0x2171300
Value: 5
C
Address: 0x7ffdd62964b0
Value: 3.14
Address: 0x2171320
Value: 5
Replace A (This leaks)
Address: 0x2171350
Value: 9.81
Address: 0x2171360
Value: 7
Derived Owns A Dynamic Resource
Now, Derived has a dynamic of its own to manage. So I follow the Rule of 3 and provide a copy constructor, destructor, and assignment operator overload. You'll notice that the assignment operator looks identical to the Base version; this is intentional.
It's because I'm using the copy/swap idiom. So in the swap() function for Derived, I add a step where it swaps the Base portion, then swaps the Derived portion. I do this by invoking the Base swap() function through the dynamic cast.
And we can again observe that all objects have their own memory for each dynamically allocated piece.
#include <iostream>
class Base {
private:
int* m = nullptr;
public:
Base() = default;
Base(int v) : m(new int(v)) {}
Base(const Base& other) : m(new int(*(other.m))) {}
virtual ~Base() {
delete m;
m = nullptr;
}
Base& operator=(Base other) {
swap(*this, other);
return *this;
}
friend void swap(Base& lhs, Base& rhs) {
using std::swap;
swap(lhs.m, rhs.m);
}
virtual void print() const {
std::cout << "Address: " << m << "\nValue: " << *m << '\n';
}
};
class Derived : public Base {
private:
double* x = nullptr;
public:
Derived() = default;
Derived(double v) : Base(), x(new double(v)) {}
Derived(int i, double v) : Base(i), x(new double(v)) {}
Derived(const Derived& other) : Base(other), x(new double(*(other.x))) {}
~Derived() {
delete x;
x = nullptr;
}
Derived& operator=(Derived other) {
swap(*this, other);
return *this;
}
friend void swap(Derived& lhs, Derived& rhs) {
using std::swap;
swap(dynamic_cast<Base&>(lhs), dynamic_cast<Base&>(rhs));
swap(lhs.x, rhs.x);
}
void print() const override {
std::cout << "Address: " << &x << "\nValue: " << *x << '\n';
Base::print();
}
};
int main() {
std::cout << "A\n";
Base* a = new Derived(5, 3.14);
a->print();
std::cout << "\nB\n";
Derived b = *(dynamic_cast<Derived*>(a)); // Copy ctor
b.print();
std::cout << "\nC\n";
Derived c;
c = b;
c.print();
std::cout << "\nReplace A (This leaks)\n";
a = new Derived(7, 9.81);
a->print();
}
Output:
A
Address: 0x14812d0
Value: 3.14
Address: 0x14812e0
Value: 5
B
Address: 0x7fffe89e8d68
Value: 3.14
Address: 0x1481320
Value: 5
C
Address: 0x7fffe89e8d50
Value: 3.14
Address: 0x1481360
Value: 5
Replace A (This leaks)
Address: 0x14813b0
Value: 9.81
Address: 0x14813c0
Value: 7
Does the output of this example help clarify your question? You could always override the operator= in the derived class as follows:
#include <cstdio>
struct Base{
virtual ~Base() = default;
virtual void operator=(const Base&) {
std::printf("Base::=\n");
}
};
struct Derived: public Base {
void operator=(const Derived&) {
std::printf("Derived::=\n");
}
void operator=(const Base&) override{
std::printf("Derived::= Base\n");
}
};
int main() {
Base* a, *b;
Derived c,d;
a = &c;
b = &d;
*a = *b; //Dispatches the call to the derived class =
Base base;
Derived derived;
derived = base; //Usual case now after operator=(const Base&) in Derived
c = d; //Usual case
Base base1, base2;
base1 = base2; //Usual case
a = &base1;
b = &base2;
*a = *b; //Usual case
}
Output:
Derived::= Base
Derived::= Base
Derived::=
Base::=
Base::=
Currently I am working on some algebra problem. I have an (almost abstract) base class from which several classes will be derived. All these classes will contain lists of numbers that are ordered in a lot of very different ways.
On the base class I want to define some operators that will be implemented for each of the derived classes. The idea is that once this library is finished, I don't have to care anymore about the intrinsics of the derived class. Once I initialize some derived class, I can refer to it by a reference (or pointer) of base-type and through that access all the derived operations.
I would like to setup rather complex algorithms, based on the operations that were defined on the base class. Therefore I want to be able to access these algorithms only via the base class. In that way it should easily generalize to many types of derived classes.
I have understood that this is exactly what object oriented programming is about, so that is why I ended up using C++.
I have setup most of what I want in a way similar to this example (works with g++):
#include <iostream>
class base;
base & gettype(const base&);
class base{
public:
int x;
int type;
base() = default;
base(int in){
this->type=0;
this->x = in;
}
virtual base & operator+= ( const base & other){
this->x += other.x;
return *this;
}
virtual base & operator+ ( const base & other){
base & ret = gettype(*this);
ret += other.x;
return ret;
}
virtual void print(){
std::cout << "base is: " << x << "\n";
}
};
class der1:public base{
public:
int a;
der1(){}
der1(int in){
this->x = in;
this->a = 2*in;
this->type=1;
}
base & operator+= ( const base & other){
std::cout <<"used der add\n";
const der1 & otherder = static_cast<const der1 &>(other);
this->x += otherder.x;
this->a += otherder.a;
return *this;
}
void print(){
std::cout << "der1 is: " << x << " " << a << "\n";
}
};
base & gettype(const base & in){
if(in.type==0){
return * new base();
}
if(in.type==1){
return * new der1();
}
}
main(){
base baseobj(2);
baseobj.print();
baseobj += baseobj;
baseobj.print();
(baseobj+baseobj).print(); //Answer is right, but there is a memory leak
der1 derobj(3);
derobj.print();
derobj += derobj;
base * test = new der1(4);
test->print();
(*test) += (*test);
test->print();
base & test2 = *test;
test2 += test2;
test2.print(); //All these print the right answers as well
delete test;
}
But there is a memory leak inside this. Whenever I do something like x=x+y, then the memory that is allocated in the gettype function is not freed anymore.
I have read that it is rather uncommon to have an operator+ function return a reference. However, I cannot make this work in a satisfactory manner when operator+ returns by value. The reason is that when it returns by value, it will return an object sliced as base object. When I define derived operator+ functions with covariant types (like in the example below), they are not used, because I only use base type references, not der1.
#include <iostream>
class base{
public:
int x;
base() = default;
base(int in){
this->x = in;
}
virtual base & operator+= ( const base & other){
this->x += other.x;
return *this;
}
virtual base operator+ ( const base & other){
base ret(*this);
ret += other.x;
return ret;
}
virtual void print(){
std::cout << "base is: " << x << "\n";
}
};
class der1:public base{
public:
int a;
der1(int in){
this->x = in;
this->a = 2*in;
}
der1 & operator+= ( const der1 & other){
this->x += other.x;
this->a += other.a;
return *this;
}
der1 operator+ ( const der1 & other){
der1 ret(*this);
ret += other.x;
return ret;
}
void print(){
std::cout << "der1 is: " << x << " " << a << "\n";
}
};
main(){
base baseobj(2);
baseobj.print();
baseobj += baseobj;
baseobj.print();
(baseobj+baseobj).print(); //This all works nicely for the base class
der1 derobj(3);
derobj.print();
base * test = new der1(4);
test->print(); //derived print function
base & test2 = *test;
test2 += test2; //base add function, because argument base&
test2.print(); //Indeed, wrong answer.
}
So is it possible to create a library that I can use in a manner similar to this:
base & x = getderived(3) // This will return a (reference/pointer to) derived type
base & y = getderived(3)
x +=y;
x = x+3*y;
//And a whole lot of other operations
delete x
delete y // I don't mine some manual memory management
I hope it is clear what I want to achieve. If you think it is impossible, I'm also happy to with that answer, then I know I have to stop looking further. (If there's no solution, I'll keep my current approach and have to work with += like operators, and skip the binary ones. This is not entirely bad)
In C++ you should never use explicit new/delete and you should follow RAII.
If I understood your issue, I would get rid of type and gettype and instead use a virtual clone:
class base
{
public:
virtual std::unique_ptr<base> clone() const
{
return std::make_unique<base>(*this);
}
};
class derived : public base
{
public:
std::unique_ptr<base> clone() const override
{
return std::make_unique<derived>(*this);
}
};
I would like to be able to copy either a derived or a base object to a derived object, and I would like the correct operator to be chosen polymorphically depending on the type of the copied object.
This code does not work, I would like b1 = (A&)b2; to use B & operator= (B const &other) because b2 is a B, but it uses B & operator= (A const &other):
#include<iostream>
using namespace std;
class A {
public:
A & operator= (A const &other) {
// Here copy A members...
cout<<"A to A"<<endl;
return *this;
}
};
class B: public A {
public:
B & operator= (A const &other) {
A::operator=(other); // Copy A members.
cout<<"A to B"<<endl;
return *this;
}
B & operator= (B const &other) {
A::operator=(other); // Copy A members.
// Here copy B members...
cout<<"B to B"<<endl;
return *this;
}
};
int main()
{
B b1, b2;
A a2;
b1 = b2;
cout<<endl;
b1 = (A&)b2;
cout<<endl;
b1 = a2;
cout<<endl;
return 0;
}
I guess I have to make something virtual but I don't find how.
I would like to be able to copy either a derived or a base object to a derived object, That is a symptom of poor design.
It's better to strive for a design where the only the leaf-level classes in a class hierarchy are instantiable. This allows you to have clean, non-virtual, assignment operator functions deal only with objects of right type.
class A {
public:
// Make A uninstantiable.
virtual ~A() = 0;
A & operator= (A const &other) {
// Here copy A members...
cout<<"A to A"<<endl;
return *this;
}
};
class B: public A {
public:
// Not necessary.
// B & operator= (A const &other) { ... }
B & operator= (B const &other) {
A::operator=(other); // Copy A members.
// Here copy B members...
cout<<"B to B"<<endl;
return *this;
}
};
Given a pointer to an abstract base class A*, I want to copy or assign it (as the base class) and have the derived copy constructor or assignment operator called. I understand copy constructors cannot be virtual, so presumably the copy constructor isn't an option for doing this, but the assignment operator is. Still, it doesn't seem to work: the following code prints
assigned a
x!
destroyed b
destroyed b
which fails to assign b.
#include <iostream>
using namespace std;
class A
{
public:
virtual void x()=0;
virtual ~A() {}
virtual A& operator=(const A& other) { cout << "assigned a" << endl; return *this;}
};
class B : public A
{
public:
virtual B& operator=(const B& other) { cout << "assigned b" << endl; return *this;}
virtual void x() { cout << "x!" << endl; }
virtual ~B() { cout << "destroyed b" << endl; }
};
int main()
{
A* a = new B();
A* aa = new B();
*aa=*a;
aa->x();
delete a;
delete aa;
return 0;
}
How to do this?
EDIT this question has been correctly answered below, but it was the wrong question. I shouldn't try to override the assignment operator because I don't want subclasses of A to assign to one another. For the simpler answer (hopefully) see C++ elegantly clone derived class by calling base class
The problem is that your B::operator= does not override the one in A. Change it to
virtual A& operator=(const A& other) { cout << "assigned b" << endl; return *this;}
and it will work. Also, try to use the override keyword when overriding member functions (requires C++11). The code won't compile if you don't override. In your case, it would have caught your mistake
error: 'virtual B& B::operator=(const B&)' marked 'override', but does not override
PS: you were probably thinking about covariant return types. In order for it to work, the signature of your function has to be the same, except the return type. E.g., this will work:
virtual B& operator=(const A& other) { cout << "assigned b" << endl; return *this;}
class Base
{
private:
int _b;
public:
Base();
Base(int b);
virtual void display();
//Assignment operator overload.
Base& operator=(const Base&);
};
Base::Base()
{
_b = 0;
}
Base::Base(int b)
{
_b = b;
}
void Base::display()
{
cout<<"base value := "<<_b<<endl;
}
Base& Base::operator=(const Base& ob)
{
//Check for self-assignment.
if(this != &ob)
{
this->_b = ob._b;
}
return *this;
}
class Derived : public Base
{
private:
int _d;
public:
Derived();
Derived(int d);
void display();
//Assignment operator overload.
Derived & operator=(const Derived& ob);
};
Derived::Derived() : Base()
{
_d = 0;
}
Derived::Derived(int d) : Base(d)
{
_d = d;
}
void Derived::display()
{
cout<<"Derived value := "<<_d<<endl;
}
Derived & Derived::operator=(const Derived& ob)
{
if(this != &ob)
{
this->_d = ob._d;
}
return *this;
}
int main()
{
Derived d1(10),d2(),d3;
//How d2 becomes lvalue and not d3 above.
d2 = d1;//Error :: expression must be modified lvalue.
//d2.display();
d3 = d1;
return 0;
}
Derived d2();
is treated as function declaration. Do this :-
Derived d1(10),d2,d3;
d2 = d1; /////ahaa it's working
The problem is your 'd2()'. The statement d2() does not create a derived object called d2 like you think it does. The correct options are:
Derived d2;
Derived d2 = Derived();
Derived d2(0); // or any other integer
The statement
Derived d2();
tells the compiler that you are defining a function which takes no arguments and returns the type Derived.
See here for a longer explanation:
error: request for member '..' in '..' which is of non-class type