**Discussion 9: More on Classes** 10/20, 10/22 [(back to course webpage)](./mcs360_fall2020.html) # Recap from previous time: The class Circle At the end of Discussion 8, I gave a Circle class definition for you guys, and here's a part of it: ```cpp #include class Circle { std::pair center; double radius; public: void dilate(double alpha) { radius *= alpha; } void shift(std::pair A) { center.first += A.first; center.second += A.second; } }; ``` But how do we actually create an object of type Circle and shift/dilate it? # Constructor: the cousin of __init__() Our class Circle from last time didn't yet contain a constructor function, so we could not really create a circle object in the `main()` function. A constructor does exactly the same thing as Python's `__init__()` method: it initializes a class! ## Constructor definition + You define a constructor using the class' name, and don't specify a return type. + For our Circle method, we can have the following constructor: ```cpp Circle(double x_center, double y_center, double R) { center = std::make_pair(x_center, y_center); radius = R; } ``` Then, inside the `main()` function, we can create a new `Circle` object by doing `Circle C(1.0, 2.0, 3.0)`: this declares a circle centered at $(1,2)$ and of radius $3$. ## Constructor overloading + There can be multiple constructor definitions (this is called function overloading). Say when someone writes `Circle C`, you want to create a unit circle centered at origin. Then, you would put in the following function as a second constructor: ```cpp Circle(){ center = std::make_pair(0,0); radius = 1.0; } ``` # Outputting a Circle by declaring `operator<<` as a friend: the cousin of __str__() If you want to be able to see a description of your circle as a string, you would need to declare the `operator<<` as a friend function of your `Circle` class. ```cpp std::ostream& operator<< (std::ostream& os, const Circle& c) { os << "Circle[(" << c.center.first << ", " << c.center.second << "), " << c.radius << "]\n"; } ``` I explained what these `std::ostream&` declarations are for in the discussion, so will skip that out over here. # Putting it all together in ONE CPP FILE This is the CPP file I provided during discussion: ```cpp #include class Circle { std::pair center; double radius; public: Circle(double x_center, double y_center, double R) { center = std::make_pair(x_center, y_center); radius = R; } // Creates a circle centered at (x,y) and radius 1 Circle(double x_center, double y_center) { center = std::make_pair(x_center, y_center); radius = 1.0; } // Creates a unit circle centered at the origin Circle(){ center = std::make_pair(0,0); radius = 1.0; } void shift(std::pair A) { center.first += A.first; center.second += A.second; } void dilate(double alpha) { radius *= alpha; } friend std::ostream& operator<< (std::ostream& os, const Circle& C) { os << "Circle[(" << C.center.first << ", " << C.center.second << "), " << C.radius << "]\n"; return os; } }; int main() { Circle C; // C is a unit circle centered at the origin Circle D(2); // D is a circle centered at the origin with radius 2 Circle E(1.4,2.5,2.3); // E is a circle centered at (1.4,2.5) with radius 2.3 std::cout << C; C.dilate(3); C.shift(std::make_pair(1,2)); std::cout << C; std::cout << D; std::cout << E; return 0; } ``` # Exercise Divide this entire code into three files: `circle.h`, `circle.cpp`, `d9.cpp`. The header file should contain the class and its attributes/methods' declaration, the `circle.cpp` file should contain the definitions of `Circle`'s methods, and the `d9.cpp` should contain the `main()` function.
circle.h ```cpp #include #ifndef circle_H #define circle_H class Circle { std::pair center; double radius; public: // general constructor: circle centered at (x,y) and radius r Circle(double center_x, double center_y, double r); // default constructor when center is not provided: centered at (0,0) and radius r Circle(double r); // default constructor when no argument is provided: center (0,0) and radius 1 Circle(); void dilate(double alpha); void shift(std::pair A); friend std::ostream& operator<< (std::ostream& os, const Circle& c); }; #endif ```
circle.cpp ```cpp #include "circle.h" // general constructor: circle centered at (x,y) and radius r Circle::Circle(double center_x, double center_y, double r) { center = std::make_pair(center_x, center_y); radius = r; } // default constructor when center is not provided: centered at (0,0) and radius r Circle::Circle(double r) { center = std::make_pair(0,0); radius = r; } // default constructor when no argument is provided: center (0,0) and radius 1 Circle::Circle() { center = std::make_pair(0,0); radius = 1.0; } void Circle::dilate(double alpha) { radius *= alpha; } void Circle::shift(std::pair A) { center.first += A.first; center.second += A.second; } std::ostream& operator<< (std::ostream& os, const Circle& c) { os << "Circle[(" << c.center.first << ", " << c.center.second << "), " << c.radius << "]\n"; } ```
d9.cpp ```cpp #include #include "circle.h" int main() { Circle C; // C is a unit circle centered at the origin Circle D(2); // D is a circle centered at the origin with radius 2 Circle E(1.4,2.5,2.3); // E is a circle centered at (1.4,2.5) with radius 2.3 std::cout << C; C.dilate(3); C.shift(std::make_pair(1,2)); std::cout << C; std::cout << D; std::cout << E; return 0; } ```
+ Note: To compile the code, you need to _link_ `circle.cpp` together with `d9.cpp`, and hence use the following to compile: ``` (base) potla@EKR:~/Desktop/mcs360$ g++ -o d9 d9.cpp circle.cpp ``` + If you don't link `circle.cpp`, you get: ``` (base) potla@EKR:~/Desktop/mcs360$ g++ -o d9 d9.cpp /tmp/cct49xft.o: In function `main': d9.cpp:(.text+0x22): undefined reference to `Circle::Circle()' d9.cpp:(.text+0x44): undefined reference to `Circle::Circle(double)' d9.cpp:(.text+0x7e): undefined reference to `Circle::Circle(double, double, double)' d9.cpp:(.text+0x91): undefined reference to `operator<<(std::ostream&, Circle const&)' d9.cpp:(.text+0xb3): undefined reference to `Circle::dilate(double)' d9.cpp:(.text+0x10f): undefined reference to `Circle::shift(std::pair)' d9.cpp:(.text+0x122): undefined reference to `operator<<(std::ostream&, Circle const&)' d9.cpp:(.text+0x135): undefined reference to `operator<<(std::ostream&, Circle const&)' d9.cpp:(.text+0x148): undefined reference to `operator<<(std::ostream&, Circle const&)' collect2: error: ld returned 1 exit status ```