7장 클래스
클래스 객체(object) : 속성과 동작을 가지고 있는 모든 물체 속성(property 또는 attribute) : 객체의 구체적인 모양을 결정짓는 성질 메소드(method) : 객체가 가지는 기능을 수행하기 위한 동작 클래스 (class) : 객체를 만들기 위한 설계도 class , struct , union 을 사용하여 클래스 정의 가능 class는 내부가 기본적으로 private 으로 설정 struct는 내부가 기본적으로 public 으로 설정 클래스 정의 class 클래스명{ 멤버 목록 // 멤버변수(속성)와 멤버함수(메소드) // private : 해당 클래스내부에서만 사용가능 // public : 클래스 내부, 외부 접근가능 }; // protected : 해당클래스와 파생클래스에서만 사용가능
클래스 private : // 해당 클래스 내부에서만 사용가능 class Date{ private : // 해당 클래스 내부에서만 사용가능 int Year , Month , Day ; // 멤버변수(속성) public : // 클래스외부 에서 사용가능 void SetDate( int yy, int mm, int dd ) // 멤버함수(메소드) { Year = yy; Month = mm; Day = dd; } void Display() // 멤버함수(메소드) cout << Year << ‘.’ << Month << ‘.’ << Day ; }; //클래스 정의 끝에 ; 꼭 붙임
객체선언 객체 선언 클래스이름 객체이름; 예) Date Today ; 객체를 통해 멤버에 접근 객체이름. 멤버 예) Today.SetDate(2010,10,8) ; // 객체를 통해 Today.Display() ; //클래스 안의 메소드에 접근 void main() { Date Today, Tomorrow ; //객체 2개 선언 Today.SetDate(2010,10,8) ; Today.Display() ; Tomorrow.SetDate(2020,11,9) ; Tomorrow.Display() ; Today.Year = 2015 ; //에러, Year가 private이므로 클래스외부에서 접근 불가 }
클래스의 멤버함수 정의 클래스 안의 함수의 정의가 길 때, 클래스 안에는 함수 선언만하고 클래스 밖에서 ::를 사용하여 함수정의가능 class Man{ private : char *name ; int age ; // 멤버변수(속성) public : void Data(char *n, int a ) ; // 멤버함수(메소드) 선언만 }; void Man::Data(char *n, int a ) // 클래스 밖에서 멤버함수 정의 { name = n ; // 클래스이름::멤버함수이름(매개변수들) age = a ; cout << name << ‘\t’ << age << endl ; } void main() { Man x ; // 객체 선언 x.Data(“Lee”, 23); // 실행결과 Lee 23 이 출력 }
클래스의 멤버함수 정의 클래스 안에서 private인지, public인지 지정하지 않으면 자동 private이 됨 클래스 밖에서 정의된 멤버함수를 inline으로 하려면 함수정의구문 또는 함수선언문에 inline을 붙임 class Date{ private : int Year , Month , Day ; // 멤버변수(속성) public : inline void DateDisp( int yy, int mm, int dd ) ; // 멤버함수(메소드) }; void Date::DateDisp( int yy, int mm, int dd ){ Year = yy ; Month = mm; Day = dd; cout << Year << ‘.’ << Month <<‘.’ << Day ; } void main() { Date Today ; // 객체 선언 Today.DateDisp(2020, 10,10); // 실행결과 2020.10.10 출력
클래스의 멤버변수 초기화 class Score{ private : char *name ; // private 멤버변수 초기화할 때 int kor, eng ; // 직접 값을 대입 불가 public : void init(char *n, int k, int e) ; // public 멤버함수를 이용 void output(); }; void Score::init(char *n, int k, int e) { name = n ; kor = k ; eng = e ; } void Score::output(){ cout << name <<‘\t’ << kor <<‘\t’ << eng << endl ; void main() { Score x ; // 객체 선언 x.init(“Lee”, 90, 80); // 객체를 통해 클래스 멤버함수 호출하여 초기화 x.output(); // 실행결과 Lee 90 80 출력
클래스멤버함수로부터의 결과값반환 class Score{ private : char name[10] ; int kor, eng ; public : void input() ; double rst_return(); }; void Score::input() { cin >> name >> kor >> eng ; } double Score::rst_return(){ return (kor+eng)/2.0 ; void main() { Score x ; // 객체 선언 x.input(); // 객체를 통해 클래스 멤버함수 호출하여 초기화 cout << x.rst_return() << endl ;
클래스멤버함수의 선택적 매개변수 일반함수의 매개변수 기본값 지정하는 방법과 동일, 매개변수의 뒤에서부터 순서대로 지정 class Default{ public : void func1( int a=1 ){ cout << a << endl ; } void func2( int a, int b=1 ){ cout << a << “, “ << b << endl ; } void func3( int a=1, int b=1 ){ cout << a << “, “ << b << endl ; } }; void main() { Default x ; // 객체 선언 x.func1(10); //a는 10 x.func1(); //a는 기본값1 x.func2(10,10); // a는 10 , b도 10 x.func2(10); // a는 10 , b는 기본값 1 x.func3(); // a는 기본값1 , b도 기본값1 }
클래스 멤버변수의 오버로드 함수의 오버로드(overload) : 같은 이름의 함수를 여러 개 정의하는 것 함수의 이름이 같더라도 인수의 개수나 데이터 형을 다르게 하여 사용 class Default{ public : void func( int a ){ cout << a << endl ; } void func( int a, int b){ cout << a << “, “ << b << endl ; } }; void main() { Default x ; // 객체 선언 x.func(10); // 첫 번째 fun 함수호출 x.func(10,20); // 두 번째 fun 함수호출 }
객체 배열 객체도 배열로 선언가능, 클래스명 객체배열명[배열크기]; class MyArray{ 객체도 배열로 선언가능, 클래스명 객체배열명[배열크기]; class MyArray{ private : int a, b; public : void init( int x, int y ){ a = x ; b = y ; } int AddFunc(){ return a+b ; } }; void main() { MyArray T[3] ; // 객체 배열선언 for(int i=0 ; i< 3 ; i++) T[i].init( i , i+1); for( i=0 ; i< 3 ; i++) cout << T[i].AddFunc() << endl ; // 실행결과 1 3 5 } a,b,init(),AddFunc() T[0] T[1] T[2]
객체포인터 객체포인터로 특정 객체의 멤버들을 참조하기 위해서는 -> 을 사용 #include <string.h> //strcpy()함수의 헤더파일 class Man{ private : char name[10] ; int age ; public : void init( char *n, int a ) ; void display(); }; void Man::init( char *n, int a ) // 클래스 밖에서 함수정의 { strcpy(name,n) ; age = a ; } //strcpy는 문자열 복사 함수 void Man::display(){ cout << name << '\t' << age << endl ; } void main() { Man m, *p ; // 객체 ,객체포인터 선언 p = &m ; // 객체포인터 초기화 m.init("Lee",23); // 클래스멤버변수 초기화 m.display(); // 객체를 통해 함수호출 p->display(); // 객체포인터를 통해 함수호출 }
함수에 객체전달 class Test_class{ private : int a ; public : void init( int i ){ a = i ; } void rst(){ cout << a+a << endl ; } }; void Adder(Test_class obj); // 일반함수 선언 void main() { Test_class obj1 ; obj1.init(100); // a에 100 저장 Adder(obj1); //일반함수 Adder에 객체를 넘겨줌 } void Adder( Test_class obj ){ // 일반함수 정의, 매개변수가 객체 obj.rst(); //클래스의 멤버함수 호출
함수에서 객체반환 class Test_class{ private : int a, b ; public : void init( int n, int m ){ a = n ; b = m ; } void Adder(){ return a+b ; } }; Test_class input(); // 일반함수 선언 void main(){ Test_class obj ; obj = input(); // 반환 값이 객체이므로 객체로 받아 저장 cout << obj.Adder() << endl ; //클래스의 멤버함수 호출 } Test_class input() //일반함수 정의 , 반환 값이 객체 { int x, y ; Test_class tmp_obj ; cin >> x >> y ; // 키보드로 입력 tmp_obj.init( x, y ); // a에 x 저장, b에 y저장 return tmp_obj ; //반환 값이 객체
클래스의 생성자 생성자(Constructor) : 객체 선언할 때 자동으로 호출되는 멤버함수 클래스이름과 같고, public으로 지정, 반환 값이 없지만 함수 정의에서 void 생략, 오버로드 가능 멤버데이터의 초기화를 위해 사용, 멤버 함수 호출이 불필요 생성자 함수 정의하지 않으면 컴파일러가 자동 만들어줌 class Test_class{ private : int a ; public : Test_class( int i ){ a = i ; } // 클래스 안에서의 생성자 함수정의 void rst(){ cout << a+a << endl ; } // 클래스 멤버함수 }; void main() { Test_class obj1(100) ; // 객체생성과 동시에 생성자 함수에게 값 전달 obj1.rst(); //클래스의 멤버함수 호출 }
생성자 함수의 매개변수 기본값지정 일반함수의 매개변수 기본값지정 방식과 동일 class Test_class{ private : char name[20] ; int kor, eng ; public : Test_class( char *n, int a, int b = 50) ; // 생성자 함수 선언 void display(); }; Test_class::Test_class(char *n, int a, int b) { // 클래스 밖 생성자 함수 정의 strcpy( name, n ) ; kor = a ; eng = b ; } void Test_class::display(){ cout << name << kor << eng << endl ; } void main() { Test_class x(“이도령”,90);// 객체 선언과 동시에 생성자 함수에게 값 전달 x.display(); // eng에 기본값 50 이 출력 }
생성자 함수의 오버로드 class Sungjuk{ private : char name[20] ; int kor, eng; float avg; public : Sungjuk( char *n, int a, int b ) ; // 생성자 함수 중복 선언 Sungjuk() ; // 기본생성자 : 매개변수가 없거나 // 모든 매개변수에 기본값이 있는 생성자 void sum_avg(){ avg = ( kor+ eng ) /2.0 ; } void display() { cout << name << kor << eng << avg << endl ; } }; Sungjuk::Sungjuk(char *n, int a, int b){ strcpy( name, n) ; kor = a ; eng =b ; } Sungjuk::Sungjuk(){ cin >> name >> kor >> eng ; } void main() { Sungjuk x(“임꺽정”,90,95);// 객체 선언과 동시에 생성자 함수에게 값 전달 Sungjuk y; x.sum_avg(); x.display(); y.sum_avg(); y.display(); }
생성자를 이용한 객체배열 초기화 class Test_class{ private : char m_data ; // 생성자의 매개변수가 하나인 경우 public : Test_class( char c ){ m_data = c ; } // 생성자 함수 정의 char memberdata_return(){ return m_data ; } }; void main() { Test_class obj[3] = {‘a’, ’b’, ’c’ } ; //객체배열선언 // 배열의 각 요소 생성자 함수에 값 전달 // Test_class obj[3] ={ Test_class(‘a’), Test_class(‘b’), Test_class(‘c’) }; for(int n=0 ;n<3; n++) cout << obj[n]. memberdata_return() << endl ; } m_data=‘a’ m_data=‘c’ m_data=‘b’ obj[0] obj[1] obj[2]
생성자를 이용한 객체배열 초기화 class Test_class{ private : char m_data1, m_data2; // 생성자의 매개변수가 2개 이상 인 경우 public : Test_class( char c1, char c2 ){ // 생성자 함수 정의 m_data1 = c1 ; m_data2 = c2 ; } char mdata1_ret(){ return m_data1 ; } char mdata2_ret(){ return m_data2 ; } }; void main() { Test_class obj[3] = { Test_class(‘a’,’b’),Test_class(‘c’,’d’),Test_class(‘e’,’f’) } ; //객체배열선언, 배열의 요소 생성자 함수에 값 전달 for( int n=0 ; n<3 ; n++ ) cout << n << obj[n]. mdata1_ret() << obj[n]. mdata2_ret() << endl ; }
생성자와 객체포인터 class Test_class{ private : int a ; public : Test_class( int i ){ a = i ; } // 생성자 함수 int Display(){ return a; } // 클래스 멤버함수 }; void main() { Test_class obj(150), *p ; //객체포인터 선언 p = &obj ; // 객체포인터에 값 배정 cout << p->Display() << endl ;//포인터를 이용해 클래스에 접근할 때->사용 } a=150,Display() obj p
생성자와 객체포인터 class Test_class{ private : int a ; public : Test_class( int i ){ a = i ; } // 생성자 함수 int Display(){ return a; } // 클래스 멤버함수 }; void main() { Test_class obj[5]= {1,2,3,0,0}; // 객체배열의 초기화 Test_class *p ; // 객체포인터 선언 p = obj ; // 객체포인터변수에 배열의 시작주소 배정 (배열이름은 주소) for( int n=0 ; n < 5 ; n++ ) { cout << p->Display() ; p++; } cout<< endl ;
클래스의 소멸자 소멸자(destructor) : 객체 사용이 종료 될 때 자동으로 호출, 수행되는 함수 생성자 함수에 의해 생성된 동적 메모리를 객체소멸 시 자동으로 해제할 때 ~클래스이름 반환형이 없어 void지만 생략하여 사용 매개변수를 갖지 않음 함수의 오버로드가 불가 소멸자를 프로그램 하지 않으면 컴파일러가 자동으로 소멸자 함수를 생성 (기본 소멸자)
클래스의 소멸자 #include <string.h> class Test_class{ private : char name[20] ; int kor, eng ; public : Test_class( char *n, int a, int b ) ; // 생성자 함수 선언 ~Test_class() ; // 소멸자 함수 선언 void display() ; }; Test_class::Test_class(char *n, int a, int b) { // 생성자 함수 정의 strcpy( name, n ) ; kor = a ; eng = b ; } Test_class::~Test_class() { // 클래스 밖에서의 소멸자 함수 정의 cout << “소멸자 수행했음” << endl ; } void Test_class::display(){ cout << name << kor << eng << endl ; } void main() { Test_class x(“이도령”, 90, 100); //객체생성, 생성자 함수 통해 초기화 x.display(); // 객체를 통해 클래스 멤버함수 호출 // 여기서 객체 소멸, 자동으로 소멸자 함수 실행 }
함수에 객체 전달 시 문제 class Test_class{ private : int a ; public : Test_class( int tmp ) // 생성자 함수 선언 { cout<< “생성자 함수 호출되었음” << endl ; a = tmp ; } ~Test_class() // 소멸자 함수 선언 { cout<< “소멸자 함수 호출되었음” << endl ; } int display(){ return a ; } }; int Mul( Test_class Tmp_obj )//call by value에 의해 객체를 복사 생성했으나 // 생성자 함수가 호출되지 않음 { return Tmp_obj.display() *2 ; } void main() { Test_class obj(5); //객체생성, 생성자 함수 통해 초기화 cout << Mul(obj) << endl ; // 값에 의한 함수 호출 }
프렌드(friend) 함수 프렌드(friend) 함수 : 클래스의 멤버함수가 아니면서 클래스의 private 데이터멤버에 접근할 수 있는 함수 class Test_class{ private : int x, y ; public : Test_class( int i , int j ); // 생성자 함수 선언 friend int sum( Test_class a ); // 프렌드 함수 선언 }; Test_class ::Test_class( int i , int j ){ x = i ; y = j ; } // 생성자 함수 정의 int sum( Test_class a ) { return a.x + a.y ; } // 프렌드 함수 정의 // 클래스 private변수 x, y에 접근 가능 void main() { Test_class obj(200,100) ; // 객체 생성, 생성자 함수 호출 cout << sum(obj) << endl ; // 실행결과 300 }