C++ Programming: chapter 7 – inheritence 2018, Spring Pusan National University Ki-Joune Li http://lik.pnu.kr
Background common 어떻게 효과적으로 처리하는 방법은 ? class Student { string name; string ID; short year; string dept; float score; }; class Professor { string name; string ID; shortage; string dept; string url; }; common 어떻게 효과적으로 처리하는 방법은 ?
Using Superclass Superclass Inheritance subclass common class Person { string name; string ID; string dept; }; Inheritance Superclass subclass class Student : public Person { short year; float score; }; class Professor : public Person { shortage; string url; }; common
Superclass A, Subclass A1, A2 Superclass의 모든 Attribute와 member function은 Subclass로 상속 class Person { string name; string ID; string dept; }; sizeof(person): 12 bytes class Student : public Person { short year; float score; }; sizeof(Student): 12 + (2+4) bytes
#include <iostream> #include <cstring> using namespace std; class Shape { public: double width; double height; void display() { cout << "Width and height are " << width << " and " << height << "\n"; } }; // Triangle is derived from Shape. class Triangle : public Shape { public: char style[20]; double area() { return width * height / 2; } void showStyle() { cout << "Triangle is " << style << "\n"; } }; #include <iostream> #include <cstring> using namespace std; int main() { Triangle t1; Triangle t2; t1.width = 4.0; t1.height = 4.0; strcpy(t1.style, "isosceles"); t2.width = 8.0; t2.height = 12.0; strcpy(t2.style, "right"); t1.showStyle(); t1.display(); cout << "Area is " << t1.area() << "\n"; t2.showStyle(); t2.display(); cout << "Area is " << t2.area() << "\n"; return 0; }
Constructor class Shape { private: double width; double height; public: void display() { cout << "Width and height are " << width << " and " << height << "\n"; } // accessor functons double getWidth() { return width; } double getHeight() { return height; } void setWidth(double w) { width = w; } void setHeight(double h) { height = h; } }; // Triangle is derived from Shape. class Triangle : public Shape { char style[20]; // now private public: // Constructor for Triangle. Triangle(char *str, double w, double h) { setWidth(w); setHeight(h); strcpy(style, str); } double area() { return getWidth() * getHeight() / 2; } void showStyle() { cout << "Triangle is " << style << "\n"; } }; int main() { Triangle t1("isosceles", 4.0, 4.0); Triangle t2("right", 8.0, 12.0); t1.showStyle(); t1.display(); cout << "Area is " << t1.area() << "\n"; t2.showStyle(); t2.display(); cout << "Area is " << t2.area() << "\n"; return 0; }
private, protected, public and class inheritance class Shape { private: double width; double height; public: void display() { cout << "Width and height are " << width << " and " << height << "\n"; } Shape(double w,double h): width(w),height(h){} // accessor functons double getWidth() { return width; } double getHeight() { return height; } }; // Triangle is derived from Shape. class Triangle : public Shape { char style[20]; // now private public: // Constructor for Triangle. Triangle(char *str, double w, double h): Shape(w,h) { strcpy(style, str); } double area() { return getWidth() * getHeight() / 2; } void showStyle() { cout << "Triangle is " << style << "\n"; } }; int main() { Triangle t1("isosceles", 4.0, 4.0); Triangle t2("right", 8.0, 12.0); t1.showStyle(); t1.display(); cout << "Area is " << t1.area() << "\n"; t2.showStyle(); t2.display(); cout << "Area is " << t2.area() << "\n"; return 0; }
private, protected, public and class inheritance class Shape { protected: double width; double height; public: void display() { cout << "Width and height are " << width << " and " << height << "\n"; } // accessor functons }; // Triangle is derived from Shape. class Triangle : public Shape { char style[20]; // now private public: // Constructor for Triangle. Triangle(char *str, double w, double h): Shape(w, h) { strcpy(style, str); } double area() { return width * height / 2; } void showStyle() { cout << "Triangle is " << style << "\n"; } }; int main() { Triangle t1("isosceles", 4.0, 4.0); Triangle t2("right", 8.0, 12.0); t1.showStyle(); t1.display(); cout << "Area is " << t1.area() << "\n"; t2.showStyle(); t2.display(); cout << "Area is " << t2.area() << "\n"; return 0; } Subclass에서만 접근 가능
private, protected, public and class inheritance Super Class Subclass private protected public 접근 불가능 접근 불가능 (강제로 접근 가능하게 선언) 접근 가능 class base { int i; // private to base public: int j, k; void seti(int x) { i = x; } int geti() { return i; } }; class derived: private base { public: base::j; // make j public again - but not k base::seti(); // make seti() public base::geti(); // make geti() public int a; // public };
Member function redefinition int main() { Shape s(4.0, 4.0); Triangle t("right", 8.0, 12.0); Regular_Triangle r(10.0); t.display(); cout<<“Area: “<<r.area() <<“\n”; cout<<“Area: “<<r.Triangle::area()<<“\n”; return 0; } class Shape { protected: double width; double height; public: Shape(double w, double h): width(w), height(h) {} void display() { cout << "Width and height are " << width << " and " << height << "\n"; } }; // Triangle is derived from Shape. class Triangle : public Shape { string style; public: // Constructor for Triangle. Triangle(double w, double h, string s): width(w), height(h), style(s) {} void display() { cout << ”Style: “<<style<<“ Width:”<<width<<“ Height: "<<height << "\n"; } double area() { width*height/2.0; } }; class Regular_Triangle : public Triangle { double side; public: // Constructor for Triangle. Regular_Triangle(double s): Triangle(s, sqrt(3.0)/2.0*s,“regular”), side(s) {} double area() { side*sqrt(3.0)/4.0; } };
Class hierarchy and type conversion FunctionA(Shape A) {…} int main() { Shape s(4.0, 4.0); Triangle t("right", 8.0, 12.0); FunctionA(t); // OK ?? FunctionB(s); // OK ?? } FunctionB(Triangle B) {…}
class hierarchy: example calculator Node: Plus (+) Times (*) Int 10*3+5 + * 10 3 5 class Node { protected: int code; public: enum {PLUS, TIME, INT}; Node(int c): code(c) {} int eval(); }; class Plus: public Node { public: Node *left, *right; Plus(Node *l, Node *r): Node(PLUS), left(l), right(r) {} }; class Times: public Node { public: Node *left, *right; Times(Node *l, Node *r): Node(TIMES), left(l), right(r) {} }; class Int : public Node { public: unsigned int value; Int(int v): Node(INT), value(v) {} };
class hierarchy: example calculator Node Plus Int Times Node Bop Int Plus Times
class hierarchy: example calculator Node Bop Int Plus Times class Plus: public Bop { public: Plus(Node *l, Node *r): Bop(PLUS, l, r) {} }; class Node { protected: const int code; public: enum {PLUS, TIME, INT}; Node(int c): code(c) {} int eval(); }; class Bop: public Node { protected: Node *left, *right; public: Bop(int c, Node *l, Node *r): Node(c), left(l), right(r) {} }; class Times: public Bop { public: Times(Node *l, Node *r): Bop(TIMES, l, r) {} };
class hierarchy: example calculator – eval() function int Node::eval() { switch(code) { case INT: return this->value; // wrong case PLUS: return this->left->eval()+this->right->eval(); // wrong case TIMES: return this->left->eval()*this->right->eval(); // wrong } } 무엇이 잘못되었는가? int Node::eval() { switch(code) { case INT: return ((Int *)this)->value; case PLUS: return ((Bop *)this)->left->eval()+((Bop *)this)->right->eval(); case TIMES: return ((Bop *)this)->left->eval()*((Bop *)this)->right->eval(); } } 무엇이 부자연스러운가?
Virtual function Node Bop Int Plus Times class Node { protected: const int code; public: enum {PLUS, TIME, INT}; Node(int c): code(c) {} virtual int eval() {return -1;} // -1 means “error” }; eval eval eval eval class Bop: public Node { protected: Node *left, *right; public: Bop(int c, Node *l, Node *r): Node(c), left(l), right(r) {} }; class Int: public Node { int value; public: Plus(Node *l, Node *r): Bop(INT, l, r) {} int eval() { return value; } }; class Times: public Bop { public: Times(Node *l, Node *r): Bop(TIMES, l, r) {} int eval() {left->eval()*right->eval();} }; class Plus: public Bop { public: Plus(Node *l, Node *r): Bop(PLUS, l, r) {} int eval() {left->eval()+right->eval();} }; 지금까지는 virtual 이 있으나 없으나 비슷함 (없는 경우: function redefinition)
Virtual function 다른 Function class Node { protected: const int code; public: enum {PLUS, TIME, INT}; Node(int c): code(c) {} virtual int eval() {return -1;} // -1 means “error” }; class Node { protected: const int code; public: enum {PLUS, TIME, INT}; Node(int c): code(c) {} int eval() {return -1;} // -1 means “error” }; #include <iostream> using namespace std; int main() { Node* node_ptr=new Node(INT); Int* int1_ptr=new Int(INT, 10); Int* int2_ptr=new Int(INT, 20); Plus* plus_ptr=new Bop(PLUS, int1_ptr, int2_ptr); int flag; cout << “Input flag: ”; cin >> flag; if (flag!=0) node_ptr=plus_ptr; else node_ptr=int1_ptr; cout<<“Evaluation result:” <<node_ptr->eval() << endl; return 0; } 다른 Function 이 문장으로는 Compile time 때 함수를 결정할 수 없음 Late Binding
C++에서 Polymorphism 객체가 무엇이냐에 따라 서로 다른 동작(또는 함수)이 수행되는 것 Overriding 조건: Pointer (왜??) Virtual Function #include <iostream> using namespace std; int main() { Node* node_ptr; Int* int1_ptr=new Int(INT, 10); Int* int2_ptr=new Int(INT, 20); Plus* plus_ptr=new Bop(PLUS, int1_ptr, int2_ptr); int flag; cout << “Input flag: ”; cin >> flag; if (flag!=0) node_ptr=plus_ptr; else node_ptr=int1_ptr; cout<<“Evaluation result:” <<node_ptr->eval() << endl; return 0; } #include <iostream> using namespace std; int main() { Node node(INT); Int int1(INT, 10); Int int2(INT, 20); Plus plus(PLUS, &int1, &int2); int flag; cout << “Input flag: ”; cin >> flag; if (flag!=0) node=plus; else node=int1; cout<<“Evaluation result:” <<node.eval() << endl; return 0; } 무슨 일이 일어날까?
Pure Virtual Function Subclass에서만 정의되는 Virtual Function Pure Virtual Function 을 가지고 있는 Class: Abstract Class Abstract Class에서는 객체를 생성할 수 없음 class Node { protected: const int code; public: enum {PLUS, TIME, INT}; Node(int c): code(c) {} virtual int eval()=0; }; class Bop: public Node { protected: Node *left, *right; public: Bop(int c, Node *l, Node *r): Node(c), left(l), right(r) {} }; class Plus: public Bop { public: Plus(Node *l, Node *r): Bop(PLUS, l, r) {} int eval() {left->eval()+right->eval();} }; #include <iostream> using namespace std; int main() { Node* node_ptr=new Node(INT); // wrong Bop bop(INT, NULL, NULL); // wrong return 0; }