I have a function (modShape) which takes an abstract base class (Shape) as an argument; within the function I want to make a copy of the input object, modify the copy, and reassign the copy to the input object so that the modifications are retained above the scope of modShape.
I have set up a clone() member function for making the initial copy and that seems to work well. Next, I modify the copy using the doubleArea() member function, and attempt to copy it back to the input object.
The base and derived classes are defined in header.h:
#ifndef HEADER_H_
#define HEADER_H_
#include <iostream>
#include <cmath>
using namespace std;
// Abstract base class.
class Shape {
public:
// Virtual functions
virtual double area() { return 0; }
virtual double perimeter() { return 0; }
virtual void doubleArea() { /* do nothing */ }
virtual Shape* clone() const = 0;
};
// Derived class.
class Circle: public Shape {
private:
double radius;
public:
Circle (double r) : radius(r) {}
double area() { return (M_PI*pow(radius,2)); }
double perimeter() { return (M_PI*2*radius); }
void doubleArea() { radius *= pow(2,0.5); }
Circle* clone() const { return new Circle(*this); }
};
#endif
The function modShape and the test code are in main.cpp:
#include <iostream>
#include "header.h"
using namespace std;
void modShape(Shape &inShape) {
// Make new Shape* from clone of inShape
// and double its area.
Shape* newShape = inShape.clone();
newShape->doubleArea();
cout << "newShape's area (after doubling): " << newShape->area() << endl;
// Copy newShape to inShape.
inShape = *newShape;
cout << "newShape copied to inShape (circ)." << endl;
cout << "inShape's area in modShape: " << inShape.area() << endl;
};
int main() {
Circle circ(2);
cout << "circ's initial area (in main): " << circ.area() << endl;
modShape(circ);
cout << "circ's final area (in main): " << circ.area() << endl;
return 0;
}
The output I get from this function is:
circ's initial area (in main): 12.5664
newShape's area (after doubling): 25.1327
newShape copied to inShape.
inShape's area in modShape(): 12.5664
circ's final area (in main): 12.5664
So clearly the assignment inShape = *newShape is not working as I expect it to. My guess is that the assignment operator being used is for the Shape class, thus not copying member variables from the derived class (like radius)? If this is the case, I think I want to define an assignment operator which will "know" that the objects are derived classes, even though they are defined as base classes, but I'm not sure how to do that. Or if there is a better solution, please let me know! Any advice is greatly appreciated.
Update: Looks like slicing is the problem, now I need to figure out how to avoid it. I thought if I defined my function to take in a pointer, things would work better:
void modShape2(Shape* inShape) {
Shape* newShape = inShape->clone();
cout << inShape->area() << endl;
inShape = newShape;
cout << inShape->area() << endl;
}
Which I set up as:
Circle *circ2 = new Circle(1);
cout << "circ2's initial area (in main): " << circ2->area() << endl;
modShape2(circ2);
cout << "circ2's final area (in main): " << circ2->area() << endl;
The output produced here is
circ2's final area (in main): 3.14159
3.14159
6.28319
circ2's final area (in main): 3.14159
In this case it seems like the copy is happening without slicing since the area is being doubled inside of the modShape2 function, but the changes are not carried through when we go out of modShape2's scope for some reason. I'm really puzzled by this!