3. C++와 객체지향 C++ 코딩 방법 객체 단위로 2 개의 파일 인터페이스 파일 구현파일 인터페이스 파일(Interface File, Header File) - .h 구현 파일 (Implementation File) - .cpp 인터페이스 파일 외부 사용자를 위한 파일 객체에게 호출 가능한 메시지가 정의됨 구현을 몰라도 이 파일만 읽고 불러서 사용할 수 있음 => 정보의 은닉 (Information Hiding) 풍부하고 제대로 된 커멘트 (주석)가 중요함 구현파일 내부 구현자를 위한 파일 Data Structure
3. C++와 객체지향 인터페이스 파일 예 enum suits {diamond, clover, heart, spade}; 타입 suit는 카드무늬 집합 중 하나 enum colors {red, black}; 타입 colors는 카드색 집합 중 하나 class card{ public: card( ); 생성자 (Constructor) 함수 ~card( ); 소멸자 (Destructor)함수 colors Color( ); 현재 카드의 색깔을 되돌려 주는 함수 bool IsFaceUp( ); 앞면이 위인지 아래인지 되돌려주는 함수 int Rank( ); 카드에 쓰인 숫자를 되돌려주는 함수 void SetRank(int x); 카드의 숫자를 x로 세팅하는 함수 void Draw( ); 카드를 화면에 그려내는 함수 void Flip( ); 카드를 뒤집는 멤버함수 private: bool Faceup; 그림이 위로 향하고 있는지 나타내는 변수 int Rval; 카드 숫자를 나타내는 변수 suits Sval; 카드 종류를 나타내는 변수 }; 멤버 함수 (Member Function) 멤버 데이터 (Member Data) Data Structure
3. C++와 객체지향 인터페이스 파일 public 섹션 private 섹션 생성자, 소멸자 함수 외부사용자와의 인터페이스 클래스 선언 파일 public 섹션 외부 사용자에게 공개된(직접 불러서 사용할 수 있는) 부분 메시지 = C++ 멤버함수 함수 프로토타입만 선언됨 구현내용을 여기에 써서는 안됨(정보의 은닉) private 섹션 외부사용자에게 비공개된( 직접 사용할 수 없는) 부분 자체 클래스의 멤버함수만이 사용할 수 있음 멤버 데이터(Member Data, State Variable, Instance Variable) 여기에 멤버함수를 정의하면 그 함수는 자체 클래스의 멤버함수만이 사용할 수 있음 생성자, 소멸자 함수 Data Structure
3. C++와 객체지향 protected 섹션 하위 클래스가 상위 클래스의 상태변수나 메시지를 사용해야 할 때가 있다. protected 섹션에 의해서 다른 클래스 객체와 자신의 하위 객체의 접근성(Accessibility)을 차별화한다. 즉, 다른 객체는 접근할 수 없지만 같은 가족인 하위 클래스 객체는 접근을 가능하게 한 것이다. 자료구조 과목과는 크게 상관 없음. C++ 시간에 공부하기 Data Structure
Implementation File (.cpp or .c or .cc) 구현 파일 예 #include "card.h" card::card( ) { Sval = diamond; 카드 종류는 다이아몬드 Rval = 7; 카드 숫자는 7로 Faceup = true; 앞면을 위로 } int card::Rank( ) { return Rval; 현재의 카드 숫자를 되돌려 줌 Interface File (.h) Implementation File (.cpp or .c or .cc) Class Declaration Class Implementation #define: 매크로 정의 #include: 다른 인터페이스 파일 포함 typedef: 타입 선언 #include: 헤더 파일 포함 클래스 내의 멤버 함수 정의 데이터/객체 선언 및 활용 (main() 함수에서…) Data Structure
3. C++와 객체지향 메시지 전달 메시지를 받을 객체 다음에 점을 찍고 메시지 명 MyCard는 객체이고 Flip( )은 그 객체가 실행할 수 있는 메시지 필요하다면 괄호 안에 파라미터를 전달 멤버함수 다음에는 파라미터가 없더라도 빈 괄호를 넣는다. void main( ) { card MyCard; 내 카드 객체 하나 만들기 MyCard.Flip( ); 내 카드여! 뒤집어라 cout << MyCard.Rank( ); card야! 현재 네 숫자가 얼마인지 화면에 찍어라. } Data Structure
3. C++와 객체지향 상속(Inheritance)과 다형성(Polymorphism) class shape Color Rotate(); Move(); Fillcolor(); class triangle class circle class rectangle Base, Height Draw(); Area(); GetBase(); Radius Draw(); Area(); GetDiameter(); Width, Length Draw(); Area(); GetWidth(); Data Structure
3. C++와 객체지향 파생 (Derived) 클래스 class triangle: public shape { public: void Draw( ); 현재 객체를 화면에 그리는 함수 float Area( ); 현재 객체의 면적을 계산하는 함수 float GetBase( ); 현재 객체의 밑변 길이를 되돌려주는 함수 private: float Base; 밑변의 길이를 나타내는 변수 float Height; 높이의 길이를 나타내는 변수 }; Data Structure
3. C++와 객체지향 triangle T; T.Rotate( ); T.Rotate( );에 의해 일단 클래스 triangle에 해당 함수가 있는지를 검색 있으면 그 클래스의 함수가 실행 없으면 상위 클래스인 클래스 shape에 해당 함수가 있는지를 검색 계속적으로 상위 클래스로 올라가면서 가장 먼저 정의된 것을 상속받음 triangle T; circle C; rectangle R; T.Draw( ); C.Draw( ); R.Draw( ); Draw라는 명령은 동일 삼각형, 원, 사각형 등 서로 다른 그림이 그려짐 Draw( )라는 동일 메시지를 클래스 별로 다른 방법으로 구현. Data Structure
3. C++와 객체지향 오버라이딩 (Overriding) 하위 클래스에서 상위 클래스와 동일한 함수를 정의 상위 클래스의 함수를 덮어 씌움 일반적인 상위 클래스 함수를, 하위 클래스가 자체 특성에 맞게 특화(Specialization)시킬 때 사용되는 기법 #include <iostream> #include “override.h” using namespace std; class Base { public: void fun(){ cout<<"base::fun()"<<endl; } }; class Deri: public Base { void fun() { cout<< " der::fun()"<<endl; class Base { public: void fun(); } class Deri: public Base { int main() { Base b; b.fun(); Deri d; d.fun(); } override.cpp override.h Data Structure
3. C++와 객체지향 오버로딩 (Overloading) 하나의 클래스 내에서 같은 이름의 멤버 메소드를 여러 개 선언 각 멤버 메소드의 Prototype이 서로 다르다. 입력 파라미터가 달라야 한다. #include <iostream> using namespace std; class Base { public: void fun(){ cout<<"base::Fun()"<<endl; } void fun(int a){ cout<< " base::Fun() - "<< a <<endl; }; int main() { Base b; b.fun(); b.fun(10); Data Structure
3. C++와 객체지향 연산자 오버로딩 (Operator Overloading) 동일한 연산자에 2개 이상의 의미를 부여 어떤 의미의 함수가 불려오는지는 호출 형태에 의해 결정 Int x, y; x = y; card c1, c2; c1 = c2; 정수 할당인 = 연산자와 카드 할당인 = 연산자는 행동 방식이 달라야 함 객체 c1, c2의 상태변수는 단순한 하나의 변수가 아닐 수 있음. 연산자 다음에 card 클래스의 객체 C가 나오면 card 클래스에서 연산자 오버로딩 된 = 연산자가 실행됨. [card.h] Class card { … void operator = (card C); // = 연산자의 우변 c2에 해당하는 것이 C } [card.cpp] void card::operator = (card C) { FaceUp = C.FaceUp; //c1.FaceUp = c2.FaceUp Rval = C.Rval; //c1.Rval = c2.Rval Sval = C.Sval; //c1.Sval = c2.Sval Data Structure
4. 절차적 설계와의 비교 객체지향 설계의 가이드 라인 문제를 풀기 위해 필요한 객체를 설정한다. 객체들 간의 유사한 속성을 파악한다. 유사한 속성을 지닌 객체를 모아서 기본 클래스를 선언한다. 기본 클래스로부터 특수 속성을 지닌 하위 클래스를 정의한다. 교재 p40,41 참조 Data Structure
4. 절차적 설계와의 비교 객체지향 언어, 절차적 언어 절차적 언어 객체지향적 언어 구조면 차이 객체지향 언어는 객체를 강조 카드 객체에게 뒤집는 작업을 시킬 것인가 절차적 언어는 작업을 강조 뒤집는 함수에게 내 카드를 전달할 것인가 절차적 언어 자주 사용되는 작업을 함수로 정의. 반복 호출에 의해 재사용성을 높임. 객체 개념이 없음 최소치를 구하는 함수, 평균값을 구하는 함수 객체지향적 언어 객체를 우선적으로 설정 계산기 객체를 일단 선언하고 그 클래스 객체가 실행할 수 있는 함수를 선언 구조면 차이 객체지향: 객체 울타리 안에 변수와 함수를 묶어버림 절차적 설계: 어느 변수가 어느 함수에 사용되는지 분간하기 힘 Data Structure
인터페이스 관점: Object=Black Box 4. 절차적 설계와의 비교 객체지향 설계의 최대 장점 인터페이스와 구현의 분리 Message1 Response1 Message2 Response2 인터페이스 관점: Object=Black Box 구현 관점: Object=Visible Data Structure
Appendix 1. Polymorphism Polymorphism Example [프로그램 A] #include <iostream> using namespace std; class Instrument { public: void play() { cout << "Instrument::play" << endl; } }; class Violin : public Instrument { cout << "Violin::play" << endl; void tune(Instrument &i) { i.play(); int main() { Violin v1; tune(v1); [프로그램 B] #include <iostream> using namespace std; class Instrument { public: virtual void play() { cout << "Instrument::play" << endl; } }; class Violin : public Instrument { void play() { cout << "Violin::play" << endl; void tune(Instrument &i) { i.play(); int main() { Violin v1; tune(v1); ‘virtual’ tells the compiler it should not perform early binding Data Structure
Appendix 1. Polymorphism Overloading A scheme of one class share the same name but have different signatures Overriding A scheme of an inherited class share the same name and the same signature of a super class Binding refers to… the association of a method invocation to the code to be executed on behalf of the invocation. In static binding (early binding), all the associations are determined at compilation time. In C compiler, only static binding is used. In C++ compiler, static binding is used by default. In dynamic binding (late binding, runtime binding), the code to be executed in response to a method invocation (i.e., a message) will not be determined until runtime. Data Structure
Appendix 1. Polymorphism Polymorphic = “of many forms” Enables “programming in the general” The same invocation can produce “many forms” of results A polymorphic function (or method) A function that has the same name for different classes of the same family but has different implementations for the various classes Polymorphism is possible because of inheritance method overriding Data Structure
Appendix 2. Sample C++ Programs [Hello.cpp] #include <iostream> using namespace std; int main() { cout << "Hello, World! I am " << 8 << " Today!" << endl; } [Hellostring.cpp] #include <string> #include <iostream> using namespace std; int main() { string s1, s2; // Empty strings string s3 = "Hello, World."; // Initialized string s4("I am"); // Also initialized s2 = "Today"; // Assigning to a string s1 = s3 + " " + s4; // Combining strings s1 += " 8 "; // Appending to a string cout << s1 + s2 + "!" << endl; } Data Structure