객체지향프로그래밍II(김정준) 중간고사 대비 (6장)
함수 중복
int sum(int a, int b) { return a + b; } // 기본 함수
int sum(int a, int b, int c) { return a + b + c; } // 매개변수 개수가 다름
double sum(double a, double b) { return a + b; } // 매개변수 타입이 다름
int main() { // 중복된 sum() 함수 호출, 컴파일러가 구분
cout << sum(2, 6);
cout << sum(2, 5, 33);
cout << sum(12.5, 33.6);
}
// 중복 실패 사례
double sum(int a, int b) { return (double)(a + b); } // 컴파일러가 구분 불가
- 함수 중복
- 동일한 이름의 함수가 공존(다형성)
- function overloading
- 함수 이름을 구분하여 기억할 필요가 없음 (i_sum, b_sum, …)
- 함수 호출을 잘못하는 실수를 줄일 수 있음
- 함수 중복이 가능한 범위
◼ 일반 함수들 사이
◼ 클래스의 멤버 함수들 사이
◼ 상속 관계에 있는 기본 클래스와 파생 클래스의 멤버 함수들 사이
- 동일한 이름의 함수가 공존(다형성)
- 함수 중복 성공 조건
- 중복된 함수들의 이름 동일
- 중복된 함수들의 매개 변수 타입이 다르거나 개수가 달라야 함
- 리턴 타입은 함수 중복과 무관
- 중복된 함수들의 이름 동일
클래스에서의 함수 중복
class Circle {
int radius;
public:
Circle() { radius = 1; }
Circle(int r) { radius = r; }
};
int main() {
Circle donut; // Circle() 생성자 호출
Circle pizza(30); // Circle(int r) 생성자 호출
}
- 생성자 함수 중복 가능
- 매개 변수를 다르게 하여 다양한 형태의 초깃값 전달 가능
- 소멸자 함수 중복 불가
- 소멸자는 매개 변수를 가지지 않음
- 한 클래스 내에서 소멸자는 오직 하나만 존재
디폴트 매개 변수(default parameter)
void msg(int id, string text="") { ... } // text의 디폴트 값 : ""
...
msg(10); // id에 10, text에 “” 전달, msg(10, “"); 호출과 동일
msg(20, "Good Morning"); // id에 20, text에 “Good Morning” 전달
msg(); // 컴파일 오류. 첫 번째 매개 변수 id에 반드시 값을 전달하여야 함
msg("Hello"); // 컴파일 오류. 첫 번째 매개 변수 id에 값이 전달되지 않았음
- 매개 변수에 값이 넘어오지 않는 경우, 디폴트 값을 받도록 선언된 매개 변수
- 일반 매개 변수 앞에 선언될 수 없음. 끝에 몰려서 선언해야 함
void calc(int a, int b=5, int c, int d=0); // 컴파일 오류
void calc(int a=0, int b, int c); // 컴파일 오류
void calc(int a, int b=5, int c=0, int d=0); // 컴파일 성공
함수 중복 간소화
Circle() { radius = 1; } // 생성자 함수 중복
Circle(int r) { radius = r; }
Circle(int r = 1) { radius = r; } // 2개의 생성자 함수를 하나의 함수로 간소화
Circle(int r) { radius = r; } // 컴파일 오류
- 디폴트 매개 변수를 이용하여 함수 중복을 간소화할 수 있음
- 디폴트 값이 있는 함수와 없는 함수는 함께 사용 불가
함수 중복의 모호성
- 함수 중복이 모호하여 컴파일러가 올바른 함수를 결정하지 못하는 경우
① 형 변환으로 인한 모호성
float square(float a) {
return a * a;
}
double square(double a) {
return a * a;
}
int main() {
cout << square(3.0); // 3.0은 double타입이므로 모호성 없음
cout << square(3); // int 타입 3을 어떤 타입으로 변환할지 모호하여 오류 발생
}
② 참조 매개 변수로 인한 모호성
int add(int a, int b) {
return a + b;
}
int add(int a, int &b) {
b = b + a;
return b;
}
int main(){
int s = 10, t = 20, sum;
sum = add(s, t); // 어떤 인자 전달 방식을 사용할지 모호하여 오류 발생
}
③ 디폴트 매개 변수로 인한 모호성
void msg(int id) {
cout << id << endl;
}
void msg(int id, string s="") {
cout << id << ":" << s << endl;
}
int main(){
msg(5, "Good Morning"); // 정상 컴파일. 두 번째 msg() 호출
msg(6); // 디폴트 매개 변수를 이용하고 있는지 모호하여 오류 발생
}
static 멤버와 non-static 멤버
- static
- 변수와 함수에 대한 기억 부류의 한 종류
◼ 생명 주기 – 프로그램이 시작될 때 생성, 프로그램 종료 시 소멸
◼ 사용 범위 – 선언된 범위, 접근 지정에 따름
- 변수와 함수에 대한 기억 부류의 한 종류
- 클래스의 멤버
- static 멤버
◼ 프로그램이 시작할 때 생성
◼ 프로그램이 종료될 때 소멸
◼ 클래스 당 하나만 생성, 클래스 멤버라고 불림
◼ 클래스의 모든 인스턴스(객체)들이 공유하는 멤버 - non-static 멤버
◼ 객체가 생성될 때 함께 생성
◼ 객체가 소멸될 때 함께 소멸
◼ 객체마다 객체 내에 생성
◼ 인스턴스 멤버라고 불림
- static 멤버
static 멤버 선언
class Person {
public:
// non-static 멤버 선언
int money; // 개인 소유의 돈
void addMoney(int money) {
this->money += money;
}
static int sharedMoney; // 공금
static void addShared(int n) {
sharedMoney += n;
}
};
// static 멤버 변수 생성 (전체 프로그램에서 한 번만 생성)
int Person::sharedMoney = 10; // 반드시 전역 변수로 생성해야 함
static 멤버 사용
Person lee;
lee.sharedMoney = 500; // 객체.static멤버 방식
Person *p; // 객체 포인터
p = &lee;
p->addShared(200); // 객체포인터->static멤버 방식
- 객체 이름이나 객체 포인터로 접근 가능
- 일반 멤버처럼 접근할 수 있음
Person::sharedMoney = 200; // 클래스명::static멤버변수명
Person::addShared(200); // 클래스명::static멤버함수명
Person::money = 100; // 컴파일 오류. non-static 멤버는 클래스명으로 접근 불가
- 클래스 이름과 범위 지정 연산자(::)로 접근 가능
- 클래스마다 오직 한 개만 생성되기 때문
static 활용
- static의 주요 활용
- 전역 변수나 전역 함수를 클래스에 캡슐화
◼ 전역 변수나 전역 함수를 가능한 사용하지 않도록 함 - 객체 사이에 공유 변수를 만들고자 할 때
◼ static 멤버를 선언하여 모든 객체들이 공유
- 전역 변수나 전역 함수를 클래스에 캡슐화
static 관련 접근 범위
class Person {
int money;
public:
static int sharedMoney;
static int getMoney() { return money; } // 컴파일 오류
// static 멤버 함수는 non-static 멤버에 접근 불가
int total() { return money + sharedMoney; } // 정상 함수
// non-static 멤버 함수는 static 멤버에 접근 가능
static void addMoney(int n) { this->money + = n; } // 컴파일 오류
// static 멤버 함수에서는 this 포인터를 사용할 수 없음
}
- static 멤버 함수가 접근할 수 있는 것
◼ static 멤버 함수
◼ static 멤버 변수
◼ 함수(자기 자신) 내의 지역 변수 - static 멤버 함수는 non-static 멤버에 접근 불가
◼ 객체가 생성되지 않은 시점에서 static 멤버 함수가 호출될 수 있기 때문 - non-static 멤버 함수는 static에 접근 가능
- static 멤버 함수는 this 사용 불가
- static 멤버 함수는 객체가 생기기 전부터 호출이 가능하기 때문