using namespace std; #include #include #include // Modern C++ version, requires g++ -std=c++14 #include using namespace std; #define PI 3.1415927 class shape // abstract class with pure virtual functions { protected: int x; int y; public: shape() {} shape(int x0, int y0): x{x0},y{y0} {} virtual double distance(shape& other) { // should this be "virtual"? int dx = x-other.x, dy = y-other.y; return sqrt(dx*dx + dy*dy); } virtual double area()= 0; // "pure virtual" (aka "abstract") virtual double circumference() = 0; // {return 0;} makes it non-abstract }; class circle : public shape // note public inheritance { protected: double radius; public: circle(int a, int b, double r) : shape(a,b) {radius=r;} double area() override { return PI*radius*radius; } // note "override" double circumference() override {return PI*radius*2;} double get_radius() { return radius; } // extra function }; class rectangle : public shape { protected: double width; double height; public: rectangle(int a, int b, double w, double h): shape(a,b) {width=w; height=h;} double area() override { return width*height; } double circumference() override {return width*2 + height*2; } }; class square : public rectangle { // rectangle with same width as height public: square(int x, int y, double w) : rectangle(x,y,w,w) {} }; class sphere : public circle { // 3D circle protected: int z; // z coordinate augments x,y public: sphere(int x, int y, int z0, int r) : circle(x,y,r), z{0} {} double distance(sphere& other) { // not override but overload int dx = x-other.x, dy = x-other.y, dz = z-other.z; return sqrt(dx*dx + dy*dy + dz*dz); } double distance(shape& other) override { // loss of static type safety here return distance(dynamic_cast(other)); //return distance((sphere&)other); //this would lose dynamic type safety too } double area() override { return PI*radius*radius*4; } int getz() { return z;} };//sphere int main() { unique_ptr S[4]; S[0] = make_unique(4,5,8); S[1] = make_unique(7,9,5,10); S[2] = make_unique(5,6,9); char x; cout << "you want a circle or something else? "; cin >> x; if (x=='c' || x=='y') S[3] = make_unique(10,10,10); else S[3] = make_unique(10,10,10); for(auto& s:S) cout << s->area() << endl; for(auto& s:S) cout << s->circumference() << endl; // Note that s is technically a reference not another pointer, which would // destroy the uniqueness of the unique_ptr. // The unique_ptr's destructor is called when it's popped from the stack, // which also deletes the heap-allocated memory that it points to. // don't ever do this in C++ because it "looks more like java": circle A = sphere(30,40,50,10); // look ma, it compiles! cout << "A's z coordinate is " << ((sphere&)A).getz() << endl; // only enough memory for a circle was allocated on the stack, not a sphere cout << (sizeof(A) == sizeof(sphere)) << endl; // false! // or this: double r = ((circle&)*S[1]).get_radius(); // compiles but what did you get? cout << "radius of circe S[1] is " << r << endl; // this is the closest you can get to java in C++: //double rad = S[0]->get_radius(); // won't compile: static type is shape double rad = (dynamic_cast(*S[0])).get_radius(); // compiles rad = (dynamic_cast(*S[1])).get_radius(); //compiles too // but results in RUNTIME type-casting error // unique pointers and "move semantics:" unique_ptr B = make_unique(3,4,5,6); //right way to do it. B = make_unique(1,2,3); // no memory leak, sphere deallocated. //unique_ptr C = B; // can't destroy uniqueness, won't compile. unique_ptr C = move(B); // B becomes nullptr, pointer stays unique return 0; }//main // What are the advantages and disadvantage of real OOP? // Advantages: loosely coupled components, extensible, // enables code sharing, polymorphic functions such as distance, // Disadvantages: requires dynamic typing, dynamic dispatch, and, most // importantly, dynamic memory allocation and deallocation from the heap. // The latter also puts pressure on languages without a garbage collector. // Another inherent disadvantage is a compromise on static type safety.