본문 바로가기

명품 C++

[명품 C++] 6. 함수 중복과 static 멤버

6.1 함수 중복

함수 중복은 다형성의 한 사례

조건

1. 중복된 함수들의 이름이 동일하여야 한다

2. 중복된 함수들은 매개 변수 타입이나 매개 변수의 개수가 달라야 한다

3. 함수 중복에 리턴 타입은 고려되지 않는다

좋은 점

작성이 편리하고 이름을 구분지어서 기억할 필요가 없다

int sum(int a, int b, int c){ //1
	return a+b+c;
}
double sum(double a, double b){ //2
	return a+b;
}
int sum(int a, int b){ //3
	return a+b;
}

int main(){
	cout << sum(2,5,33); //1
    cout << sum(12.5,33.6); //2
    cout << sum(2,6); //3
}

예제 6-1)

#include <iostream>
using namespace std;

int big(int a, int b){
    if (a>b) return a;
    else return b;
}

int big(int a[], int size){
    int res = a[0];
    for (int i=1;i<size;i++){
        if (res<a[i]){
            res=a[i];
        }
    }
    return res;
}


int main(){
    int array[5]={1,9,-2,8,6};
    cout << big(2,3) << "\n";
    cout << big(array,5) << "\n";
}

예제 6-2)

#include <iostream>
using namespace std;

int sum(int a, int b){
    int result=0;
    for (int i=a;i<=b;i++){
        result += i;
    }
    return result;
}

int sum(int a){
    int result = 0;
    for (int i=0;i<=a;i++){
        result += i;
    }
    return result;
}


int main(){
    cout << sum(3,5) << "\n";
    cout << sum(3) << "\n";
    cout << sum(100) << "\n";
}

생성자 함수는 중복이 가능하다 >> 이미 그렇게 써왔음

소멸자 함수는 중복이 불가능하다

 

 

 

6.2 디폴트 매개 변수

매개 변수 = 디폴트 값 형태로 선언된다

디폴트 매개 변수에 디폴트 값을 전달하는 것은 컴파일러가 한다

void star(int a=5); //디폴트 값 5

디폴트 매개 변수를 가진 함수를 선언할 때, 디폴트 매개 변수는 모두 끝 쪽에 몰려 선언되어야 한다.

void calc(int a, int b=5, int c, int d=0) //error
void calc(int a,int b=5, int c=0, int d=0) //success

예제 6-4)

#include <iostream>
using namespace std;

void f(char c=' ', int line = 1);

void f(char c, int line){
    for (int i=0;i<line;i++){
        for (int j=0;j<10;j++){
            cout << c;
        }
        cout << "\n";
    }
}

int main(){
    f();
    f('%');
    f('@',5);
}

디폴트 매개 변수를 가진 함수는 같은 이름의 중복 함수들과 함께 선언될 수 없다.

디폴트 매개 변수의 최대 장점은 함수 중복을 간소화 할 수 있다는 점

예제 6-5)

#include <iostream>
using namespace std;

void fillLine(int n=25, char c='*'){
    for (int i=0;i<n;i++){
        cout << c;
    }
    cout << "\n";
}

int main(){
    fillLine();
    fillLine(10, '%');
}

예제 6-6)

#include <iostream>
using namespace std;

class MyVector{
    int *p;
    int size;
public:
    MyVector(int n=100){
        p= new int [n];
        size = n;
    }
    ~MyVector(){
        delete [] p;
    }
};

int main(){
    MyVector *v1, *v2;
    v1 = new MyVector();
    v2 = new MyVector(1024);
    
    delete v1;
    delete v2;
}

 

 

 

6.3 함수 중복의 모호성

함수 중복으로 인한 모호성은 3가지가 있다

1. 형 변환으로 인한 모호성

char -> int -> long -> float -> double (왼쪽에 있는 타입이 오른쪽에 있는 어떤 타입으로도 자동 형 변환 가능하다)

float square(float a);
double square(double a);

정수를 float 타입으로 형변환할지 double 타입으로 할지 모호한 경우 컴파일 오류가 발생한다

2. 참조 매개 변수로 인한 모호성

int add(int a, int b);
int add(int a, int &b);

int s=10, t=20;
add(s,t); //컴파일 오류

3. 디폴트 매개 변수로 인한 모호성

void msg(int id);
void msg(int id, string s="");

msg(6); //컴파일 오류, 둘 중 어느 것을 컴파일 해도 괜찮기 때문에

 

 

 

6.4 static 멤버

static은 변수와 함수 생명 주기와 사용 범위를 지정하는 방식 중 하나

생명 주기 - 프로그램이 시작할 때 생성되고 프로그램이 종료할 때 소멸

사용 범위 - 변수나 함수가 선언된 범위 내에서 사용. 전역 혹은 지역으로 구분

static 멤버는 클래스 당 하나만 생기고 모든 객체들이 공유하므로 클래스 멤버로 부를 수 있다

non-static 멤버는 각 객체마다 별도로 생성되므로 인스턴스라고 부른다

static 멤버 선언

class Person{
public:
	int money; //각 person 객체의 돈을 표현
    void addMoney(int money){
    	this->money +=money;}
    static int sharedMoney; //모든 객체들이 공유하는 공금 
    static void addShared(int n){
    	sharedMoney += n;
    }
};

int Person::sharedMoney = 10; //static 변수 공간 할당. 반드시 프로그램의 전역 공간에 선언

static 멤버 사용

객체 이름이나 객체 포인터를 사용하여 보통 멤버와 동일하게 다루면 된다

Person lee;
lee.sharedMoney = 500;

Person *p;
p = &lee;
p->addShared(200);

클래스명과 범위지정 연산자(::)로도 접근이 가능하다

Person::sharedMoney = 200;
Person::addShared(200);

static 멤버들은 객체가 생기기 전부터 사용이 가능

static의 활용

1. 캡슐화

class Math{
public:
	static int abs(int a){ return a>0? a:-a;}
    static int max(int a, int b) { return (a>b)?a:b;}
    static int min(int a, int b) { return (a>b)?b:a;}
};

int main(){
	cout << Math::abs(-5) << "\n";
    cout << Math::max(10, 8) << "\n";
}

2. 객체 사이에 공유 변수를 만들고자 할 때

#include <iostream>
using namespace std;

class Circle{
    static int num;
    int radius;
public:
    Circle (int r=1){
        radius = r;
        num++;
    };
    ~Circle(){
        num--;
    }
    double getArea(){
        return 3.14*radius*radius;
    }
    static int getNum(){
        return num;
    }
};


int Circle::num = 0;

int main(){
    Circle *p = new Circle[10];
    cout << Circle::getNum() << "\n";
    
    delete [] p;
    cout << Circle::getNum() << "\n";
    
    Circle a;
    cout << Circle::getNum() << "\n";
    
    Circle b;
    cout << Circle::getNum() << "\n";
}

static 멤버 함수의 특징

1. static 멤버 함수는 오직 static 멤버들만 접근

2. static 함수는 this를 사용할 수 없다

 

 

 

openchallenge

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
using namespace std;
class Person{
    string name;
public:
    void setName(string name) { this->name=name; }
    string getName() { return name; }
};

class UpAndDownGame{
    static int n, left, right;
public:
    static void game();
};

int UpAndDownGame::n = rand()%100;
int UpAndDownGame::left = 0;
int UpAndDownGame::right = 99;

void UpAndDownGame::game(){
    cout << "Up&Down 게임을 시작합니다." << "\n";
    Person p[2];
    p[0].setName("김인수");
    p[1].setName("오은경");
    int i=0;
    bool solve =true;
    for(; ;){
        cout << "답은 " << left << "과 " << right << "사이에 있습니다." << endl;
        cout << p[i % 2].getName() << ">>";
        int num = 0;
        cin >> num;
        if (num < UpAndDownGame::n)
            UpAndDownGame::left = num;
        else if (num > UpAndDownGame::n)
            UpAndDownGame::right=num;
        else if (num == UpAndDownGame::n) {
            cout << p[i % 2].getName() << "가 이겼습니다!!" << endl;
            break;}
        ++i;
        }
}


int main() {
    srand((unsigned)time(0));
    UpAndDownGame::game();
}

 

 

 

 

실습문제

1-1

#include <iostream>
using namespace std;
int add (int *a, int size){
    int sum=0;
    for (int i=0;i<size;i++){
        sum += a[i];
    }
    return sum;
}

int add (int *a, int size, int *b){
    int sum=0;
    for (int i=0;i<size;i++){
        sum += a[i];
        sum += b[i];
    }
    return sum;
}


int main() {
    int a[] = {1,2,3,4,5};
    int b[] = {6,7,8,9,10};
    int c = add(a,5);
    int d = add(a,5,b);
    cout << c << "\n";
    cout << d << "\n";
}

1-2

#include <iostream>
using namespace std;

int add (int *a, int size, int *b=NULL){
    int sum=0;
    for (int i=0;i<size;i++){
        sum += a[i];
    }
    if (b!=NULL){
        for (int i=0;i<size;i++){
            sum += b[i];
        }
    }
    return sum;
}


int main() {
    int a[] = {1,2,3,4,5};
    int b[] = {6,7,8,9,10};
    int c = add(a,5);
    int d = add(a,5,b);
    cout << c << "\n";
    cout << d << "\n";
}

2

#include <iostream>
using namespace std;
class Person{
    int id;
    double weight;
    string name;
public:
    Person(int id=1,string name="Grace", double weight=20.5){
        this->id=id;
        this->name=name;
        this->weight=weight;
    }
    void show() {
        cout << id << ' ' << weight << ' ' << name << "\n";
    }
};


int main() {
    Person grace, ashley(2,"Ashley"), helen(3,"Helen", 32.5);
    grace.show();
    ashley.show();
    helen.show();
}

3

1-1)

#include <iostream>
using namespace std;
int big (int a, int b){
    int bigger = 0;
    if (a<b){
        bigger = b;}
    else {
        bigger = a;
    }
    int result = 0;
    
    if (bigger < 100){
        result = bigger;
    }
    else if (bigger > 100){
        result = 100;
    }
    
    return result;
}

int big(int a, int b, int c){
    int bigger = 0;
    if (a<b){
        bigger = b;}
    else {
        bigger = a;
    }
    
    int result = 0;
    if (bigger < c){
        result = bigger;
    }
    else if (bigger > c){
        result = c;
    }
    
    return result;
}


int main() {
    int x = big(3, 5);
    int y = big(300, 60);
    int z = big(30, 60, 50);
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

1-2)

#include <iostream>
using namespace std;

int big(int a, int b, int c=100){
    int bigger = 0;
    if (a<b){
        bigger = b;}
    else {
        bigger = a;
    }
    
    int result = 0;
    if (bigger < c){
        result = bigger;
    }
    else if (bigger > c){
        result = c;
    }
    
    return result;
}


int main() {
    int x = big(3, 5);
    int y = big(300, 60);
    int z = big(30, 60, 50);
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

4

#include <iostream>
using namespace std;

class MyVector{
    int *mem;
    int size;
public:
    MyVector(int n=100, int val=0){
        mem = new int [n];
        size = n;
        for (int i=0;i<size;i++){
            mem[i]=val;
        }
    }
    ~MyVector(){
        delete [] mem;
    }
    void show(){
        for (int i = 0; i < size; i++) {
                cout << mem[i] << ' ';
            }
        cout << "\n";
    }
};
int main() {
    MyVector a, b(10, 1);
    a.show();
    b.show();
}

5

#include <iostream>
using namespace std;

class ArrayUtility {
public:
    static void intToDouble(int source[], double dest[], int size);
    static void doubleToInt(double source[], int dest[], int size);
};

void ArrayUtility::intToDouble(int source[], double dest[], int size){
    for(int i=0;i<size;i++){
        dest[i] = (double)source[i];
    }
}

void ArrayUtility::doubleToInt(double source[], int dest[], int size){
    for (int i=0;i<size;i++){
        dest[i] = (int) source[i];
    }
}

int main() {
    int x[] = { 1,2,3,4,5 };
    double y[5];
    double z[] = { 9.9, 8.8, 7.7, 6.6, 5.6 };

    ArrayUtility::intToDouble(x, y, 5);
    for (int i = 0; i < 5; i++)cout << y[i] << ' ';
    cout << "\n";

    ArrayUtility::doubleToInt(z, x, 5);
    for (int i = 0; i < 5; i++)cout << x[i] << ' ';
    cout << "\n";
}

6

#include <iostream>
using namespace std;

class ArrayUtility2 {
public:
    static int* concat(int s1[], int s2[], int size);
    static int* remove(int s1[], int s2[], int size, int& retSize);
};

int* ArrayUtility2::concat(int s1[], int s2[], int size){
    int* result = new int [size];
    int index=0;
    cout << "합친 정수 배열을 출력한다\n";
    for (int i=0;i<size/2;i++){
        result[index] = s1[i];
        cout << result[index]<<' ';
        index++;
    }
    for (int i=0;i<size/2;i++){
        result[index] = s2[i];
        cout << result[index] << ' ';
        index++;
    }
    cout << "\n";
    return result;
}

int* ArrayUtility2::remove(int s1[], int s2[], int size, int& retSize){
    int cnt = 0;
    int* result = new int[size];

    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            if (s1[i] == s2[j]) break;
            if (j == size-1)
                result[cnt++] = s1[i];
            }
        }

    retSize = cnt;
    cout << "배열 x[]에서 y[]를 뺀 결과를 출력한다. 개수는 " << retSize << endl;
    int* ret = new int[retSize];
    for (int i = 0; i < retSize; i++) {
        ret[i] = result[i];
        cout << ret[i] << ' ';
    }
    cout << "\n";

    return ret;
}

int main() {
    int x[5], y[5], retSize;
    int* z, *w;

    cout << "정수를 5개 입력하라. 배열 x에 삽입한다>>";
    for (int i = 0; i < 5; i++) {
        cin >> x[i];
    }
    cout << "정수를 5개 입력하라. 배열 y에 삽입한다>>";
    for (int i = 0; i < 5; i++) {
        cin >> y[i];
    }
    z = ArrayUtility2::concat(x, y, 10);
    w = ArrayUtility2::remove(x, y, 5, retSize);
    
}

7

#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;

class Random {
public:
    static void seed() { srand((unsigned)time(0)); }
    static int nextInt(int min = 0, int max = 32767);
    static char nextAlphabet();
    static double nextDouble();
};

int Random::nextInt(int min, int max){
    return rand()&(max-min)+min;
}

char Random::nextAlphabet(){
    if (rand()%2==0) return rand()%26+'a';
    else return rand()%26+'A';
}

double Random::nextDouble(){
    return (double) rand()/RAND_MAX;
}



int main() {
    cout << "1에서 100까지 랜덤한 정수 10개를 출력합니다" << endl;
    for (int i = 0; i < 10; i++) {
        cout << Random::nextInt(1, 100) << ' ';
    }
    cout << "\n";

    cout << "알파벳을 랜덤하게 10개 출력합니다" << endl;
    for (int i = 0; i < 10; i++) {
        cout << Random::nextAlphabet() << ' ';
    }
    cout << "\n";

    cout << "랜덤한 실수 10개를 출력합니다" << endl;
    for (int i = 0; i < 10; i++) {
        cout << Random::nextDouble() << ' ';
    }
    cout <<"\n";
}

8

#include <iostream>
#include <string>
using namespace std;

class Trace{
public:
    static string log[100][20];
    static int index;
    static void put(string tag,string str);
    static void print(string tag="");
};
string Trace::log[100][20] = { "" };
int Trace::index = 0;

void Trace::put(string tag, string str){
    log[index][0] = tag;
    log[index][1] = str;
    index++;
}

void Trace::print(string tag){
    if (!tag.empty()){
        cout << "---" << tag << "태그의 Trace 정보를 출력합니다. ---\n";
        for (int i=0;i<index;i++){
            if (log[i][0].compare(tag)==0){
                cout << log[i][0] << ":" << log[i][1] << "\n";
            }
        }
    }
    else{
        cout << tag << "--- 모든 Trace 정보를 출력합니다. --- \n";
        for (int i=0;i<index;i++){
            cout << log[i][0] << ":" << log[i][1] << "\n";
        }
    }
}


void f() {
    int a, b, c;
    cout << "두 개의 정수를 입력하세요>>";
    cin >> a >> b;
    Trace::put("f()", "정수를 입력 받았음");
    c = a + b;
    Trace::put("f()", "합 계산");
    cout << "합은 " << c << endl;
}

int main() {
    Trace::put("main()", "프로그램 시작합니다");
    f();

    Trace::put("main()", "종료");
    Trace::print("f()");
    Trace::print();
    return 0;
}

9

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

class Board {
public:
    static string *notices;
    static int index;
    static void add(string str);
    static void print();
};

string* Board::notices = new string[100];
int Board::index = 0;

void Board::add(string str) {
    notices[index++] = str;
}

void Board::print() {
    cout << "******** 게시판입니다. ********" << "\n";
    for (int i = 0; i < index; i++) {
        cout << i << ": " << notices[i] << "\n";
    }
    cout << "\n";
}

int main() {
    Board::add("중간고사는 감독 없는 자율 시험입니다.");
    Board::add("코딩 라운지 많이 이용해 주세요.");
    Board::print();
    Board::add("진소린 학생이 경진대회 입상하였습니다. 축하해주세요");
    Board::print();
}