C/C++ 학습 · 12 min read · Oct 10, 2025

C/C++ 단계별 학습 - 페이지 13

13. 단계별 C/C++ — C++ 프로그래밍 - OOPs

OOP (객체 지향 프로그래밍) in C++

| | 1. 객체 지향 패러다임

  1. 객체 지향 언어의 특성
  • 객체
  • 클래스
  • 데이터 추상화
  • 데이터 캡슐화
  • 상속
  • 다형성
  • 동적 바인딩
  • 메시지 전달
  1. C++의 역사
  2. 클래스와 객체
  3. 클래스 외부에 정의된 멤버 함수
  4. 객체 배열
  5. 인수로서의 객체
  6. 함수에서 객체 반환
  7. 생성자
  8. 소멸자
  9. 생성자 오버로딩
  10. 정적 클래스 데이터
  11. 정적 멤버 함수
  12. 친구 함수 |

1. 객체 지향 패러다임

객체 지향 패러다임의 기본 아이디어는 데이터를 조작하는 함수와 데이터를 단일 단위로 결합하는 것입니다. 이러한 단위를 객체라고 합니다.

이 방법을 통해 우리는 데이터를 직접 접근할 수 없습니다. 데이터는 숨겨져 있으므로 우발적인 변경으로부터 안전합니다. 데이터와 그 함수는 단일 엔티티로 캡슐화되어 있다고 합니다. 데이터 캡슐화와 데이터 숨김은 객체 지향 언어의 설명에서 핵심 용어입니다.

C++ 프로그램은 일반적으로 서로의 멤버 함수를 호출하여 통신하는 여러 객체로 구성됩니다. C++ 프로그램의 조직은 이 그림에 나타나 있습니다.

| | |

2. 객체 지향 언어의 특성

여기 객체 지향 언어의 몇 가지 주요 요소가 있습니다.

| | - 객체

  • 클래스
  • 데이터 추상화
  • 데이터 캡슐화
  • 상속
  • 다형성
  • 동적 바인딩
  • 메시지 전달 |

| |
객체
객체는 클래스의 인스턴스입니다. 데이터와 멤버 함수를 결합합니다. 객체는 객체 지향 시스템의 기본 런타임 엔티티입니다. | | |
클래스
객체의 특성을 정의하고 객체가 어떻게 보이고 행동해야 하는지를 설명하는 템플릿 또는 청사진입니다. | | |
데이터 추상화
클래스나 객체에 대한 모든 정보를 처리하지 않고도 클래스나 객체의 구별되는 특성을 식별하는 것입니다. 예를 들어, 테이블 탐색 버튼 세트를 생성할 때, 개별 구성 요소와 그 상호 작용을 추적하는 대신 단일 엔티티로 사용할 수 있습니다. | | |
데이터 캡슐화
객체에 대한 정보(내부 데이터 구조 및 코드 등)를 포함하고 숨길 수 있는 객체 지향 프로그래밍 용어입니다. 캡슐화는 객체의 작업의 내부 복잡성을 애플리케이션의 나머지 부분과 분리합니다. 예를 들어, 명령 버튼에서 캡션 속성을 설정할 때 문자열이 어떻게 저장되는지 알 필요가 없습니다. | | |
상속
객체 지향 프로그래밍 용어입니다. 서브클래스가 기반이 되는 클래스의 특성을 취할 수 있는 능력입니다. 부모 클래스의 특성이 변경되면, 기반이 되는 서브클래스는 이러한 특성을 상속받습니다.
기본 클래스의 특성을 파생 클래스에 상속합니다. | | |
다형성
객체 지향 프로그래밍 용어입니다. 관련 클래스에 대해 동일한 이름을 가진 메서드를 가지되, 내용이 다른 능력입니다. 사용해야 할 절차는 객체의 클래스에 의해 런타임에 결정됩니다. 예를 들어, 관련 객체는 모두 Draw 메서드를 가질 수 있습니다. 매개변수로 전달된 절차는 매개변수가 어떤 유형의 객체인지 알 필요 없이 Draw 메서드를 호출할 수 있습니다. | | |
동적 바인딩
동적은 절차 호출을 호출에 대한 응답으로 실행될 코드에 연결하는 것을 의미합니다. 동적 바인딩은 주어진 절차 호출과 관련된 코드가 런타임의 호출 시점까지 알려지지 않음을 의미합니다. 이는 다형성과 상속과 관련이 있습니다. 다형적 참조와 관련된 함수 호출은 해당 참조의 동적 유형에 따라 달라집니다. | | |
메시지 전달
객체 지향 프로그램은 서로 통신하는 객체 집합으로 구성됩니다. 따라서 객체 지향 언어로 프로그래밍하는 과정은 다음과 같은 기본 단계를 포함합니다:

  1. 객체와 그 행동을 정의하는 클래스 생성.
  2. 클래스 정의에서 객체 생성.
  3. 객체 간의 통신 설정. |

3. C++의 역사

연도언어개발자비고
1960ALGOL국제 위원회너무 일반적, 너무 추상적
1963CPL케임브리지 대학교배우기 어렵고, 구현하기 어려움
1967BCPL마틴 리차드특정 문제만 처리 가능

| 1970 | B | 켄 톰프슨
AT & T 벨 연구소 | 특정 문제만 처리 가능 | | 1972 | C | 데니스 리치
AT & T 벨 연구소 | BCPL과 B의 일반성을 잃음 | | 80년대 초 | C++ | 비야르네 스트롭스트럽
AT & T | OOPs 도입. |

C++는 객체 지향 프로그래밍 언어입니다. 처음에는 ‘클래스가 있는 C’라는 이름으로, C++는 비야르네 스트롭스트럽에 의해 AT & T 벨 연구소에서 뉴저지주 머리 힐에서 80년대 초에 개발되었습니다.

스트롭스트럽은 Simula67(객체 지향 프로그래밍 언어)의 팬이자 C의 강력한 지지자로서 두 언어의 장점을 결합하여 C의 더 강력하고 우아한 버전을 만들고자 했습니다. 그 결과가 C++입니다.

C++는 진정한 객체 지향 언어입니다. 따라서 클래스와 객체의 집합이어야 합니다.

4. 클래스와 객체

클래스는 데이터와 그 관련 함수들을 함께 묶는 방법입니다. 필요할 경우 외부 사용으로부터 데이터를 숨길 수 있습니다. 클래스를 정의할 때, 우리는 다른 내장 데이터 유형처럼 취급될 수 있는 새로운 추상 데이터 유형을 생성하고 있습니다. 일반적으로 클래스 사양은 두 부분으로 구성됩니다:

| | 1. 클래스 선언

  1. 클래스 함수 정의 |

선언은 클래스의 데이터와 멤버 함수의 유형과 범위를 지정합니다. 정의는 함수의 실행 가능한 코드를 지정합니다.

클래스 선언의 일반 형식은 다음과 같습니다:

| | class class_name
{
private:
변수 선언;
함수 선언;
public:
변수 선언;
함수 선언;
}; |

클래스 선언은 구조체 선언과 유사합니다. 키워드 class는 데이터와 함수가 기본적으로 private임을 지정합니다. 반면에 struct 키워드는 데이터와 함수가 기본적으로 public임을 지정합니다. 키워드 private와 public은 가시성 레이블로 알려져 있습니다.

| | |

여기 직원 클래스를 구현하기 위한 예제 클래스가 있습니다.

| | |

다음은 emp 클래스의 전체 프로그램입니다.

| | // 직원 정보를 수집하고 표시하는 프로그램
#include
using namespace std;
class emp
{
private:
int eno;
char name[10];
float sal;
public:
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal; }
};
int main()
{
emp e;
e.getdata();
e.putdata();
return 0;
} |

5. 클래스 외부에 정의된 멤버 함수

클래스 외부에서 범위 해석 연산자(::)를 사용하여 멤버 함수를 정의할 수 있는 가능성이 있습니다.

| | // 직원 정보를 수집하고 표시하는 프로그램
#include
using namespace std;
class emp
{
private:
int eno;
char name[10];
float sal;
public:
void getdata();
void putdata();
};
void emp::getdata()
{ cin >> eno >> name >> sal; }
void emp::putdata()
{ cout << eno << name << sal; }
int main()
{
emp e;
e.getdata();
e.putdata();
return 0;
} |

6. 객체 배열

C++ 컴파일러는 객체 배열도 지원합니다.
아래 예제는 배열을 사용하여 객체의 장점을 설명합니다.

| | // 직원 정보를 수집하고 표시하는 프로그램
#include
using namespace std;
class emp
{
private:
int eno;
char name[10];
float sal;
public:
void getdata()
{ cin << eno << name << sal; }
void putdata()
{ cout >> eno >> name >> sal; }
};

int main()
{
emp e[10]; // 객체 배열 선언
for(i = 0; i <10; i++) // 객체 속성과 메서드 접근
e[i].getdata();
for(i = 0; i< 10; i++)
e[i].putdata();
return 0;
} |

7. 인수로서의 객체

함수에 객체를 전달하는 것은 구조체, 배열을 함수에 전달하는 것과 유사합니다. 다음 프로그램은 객체가 함수에 전달되는 방법을 보여줍니다.

| | // 직원 정보를 수집하고 표시하는 프로그램
#include
using namespace std;
class emp
{
private:
int eno;
char name[10];
float sal;
public:
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal; }
};
void operate(emp t);
int main()
{
emp e;
operate(e);
}
void operate(emp t)
{
t.getdata();
t.putdata();
return 0;
} |

8. 함수에서 객체 반환

우리는 객체가 함수에 인수로 전달되는 것을 보았고, 이제 함수에서 객체를 반환하는 방법에 대해 논의할 것입니다.

| | // 직원 정보를 수집하고 표시하는 프로그램
#include
using namespace std;
class emp
{
private:
int eno;
char name[10];
float sal;
public:
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal; }
};
emp get();
void put(emp t);
int main()
{
emp e;
e = get();
put(e);
return 0;
}
emp get()
{
emp t;
t.getdata();
return t;
}
void put(emp t)
{
t.putdata();
} |

9. 생성자

다음 예제는 객체의 데이터 항목에 값을 제공하는 두 가지 방법을 보여줍니다. 그러나 때때로 객체가 처음 생성될 때 별도의 멤버 함수 호출 없이 스스로 초기화할 수 있다면 편리합니다.

자동 초기화는 생성자라는 특별한 멤버 함수를 사용하여 수행됩니다. 생성자는 객체가 생성될 때 자동으로 실행되는 멤버 함수입니다.

| | // 생성자를 사용하여 직원 정보를 수집하고 표시하는 프로그램
#include
#include
using namespace std;
class emp
{
private:
int eno;
char name[10];
float sal;
public:
emp() { ; } // 인수 없는 생성자
emp(int teno, char tname[10], float tsal) // 인수가 있는 생성자
{
eno = teno;
strcpy(name, tname);
sal = tsal;
}
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal << endl; }
};

int main()
{
emp e1(1001, “Magic”, 6700.45);
emp e2;
e2.getdata();
e1.putdata();
e2.putdata();
return 0;
} |

위의 예제 프로그램은 생성자와 멤버 함수를 사용하여 두 가지 방법으로 값을 수집합니다. 객체가 선언될 때마다 생성자를 사용하여 주어진 값으로 자동으로 초기화됩니다. 반면에 객체 e2는 멤버 함수만으로 접근할 수 있습니다.

생성자의 사용을 구별하기 위한 또 다른 예제입니다.

| | // 객체는 카운터 변수를 나타냅니다.
#include
using namespace std;
class counter
{
private:
int count; // 변수 count
public:
counter() { count = 0; } // 생성자
void inc_count() { count++; } // 카운트 증가
int get_count() { return count; } // 카운트 반환
};
int main()
{
counter c1, c2; // 정의 및 초기화
cout << “\nC1 = “ << c1.get_count(); // 표시
cout << “\nC2 = “ << c2.get_count();
c1.inc_count(); // c1 증가
c2.inc_count(); // c2 증가
c2.inc_count(); // c2 증가
cout << “\nC1 = “ << c1.get_count(); // 다시 표시
cout << “\nC2 = “ << c2.get_count();
return 0;
} |

| | 생성자는 다음과 같은 특성을 가집니다.

  • 자동 초기화
  • 반환 값이 허용되지 않음
  • 클래스와 동일한 이름
  • 형식에 대한 혼란 |

10. 소멸자

소멸자는 생성자와 동일한 이름(클래스 이름과 동일)으로, 물결 기호(~)가 앞에 붙습니다:

| | // 소멸자 시연
#include
using namespace std;
class temp
{
private:
int data;
public:
temp() { data = 0; } // 생성자 (클래스와 동일한 이름)
~temp() { } // 소멸자 (물결 기호가 있는 동일한 이름)
}
int main()
{
temp t;
return 0;
} |

11. 생성자 오버로딩

관련 클래스에 대해 동일한 이름을 가진 함수가 있지만 내용이 다른 능력입니다. 사용할 절차는 객체의 클래스에 의해 런타임에 결정됩니다.

| | // 생성자 오버로딩 시연
#include
using namespace std;
class ttime
{
private:
int hh, mm, ss;
public:
ttime() {hh = 0; mm = 0; ss = 0; } // 초기화가 있는 생성자
ttime(int h, int m, int s) // 3개의 인수가 있는 생성자
{
hh = h; mm = m ; ss = s;
}
ttime(int h, int m) // 2개의 인수가 있는 생성자
{
hh = h; mm = m; ss = 0;
}
ttime(int h) // 1개의 인수가 있는 생성자
{
hh = h; mm = 0; ss = 0;
}
~ttime() { }
void get_time()
{
cin >> hh >> mm >> ss;
}
void put_time()
{
cout << endl << hh << “  “ << mm << “  “ <<  ss;
}
};
int main()
{
ttime t1, t2(12, 12, 12), t3(4, 5), t4(11); // 생성자 호출
t1.get_time();
t1.put_time();
t2.put_time();
t3.put_time();
t4.put_time();
return 0;
} |

12. 정적 클래스 데이터

클래스에서 데이터 항목이 정적으로 정의되면, 객체가 몇 개가 있든지 전체 클래스에 대해 단 하나의 항목만 생성됩니다. 정적 데이터 항목은 동일한 클래스의 모든 객체가 공통 정보를 공유해야 할 때 유용합니다. 정적으로 정의된 멤버 변수는 일반 정적 변수와 유사한 특성을 가집니다: 클래스 내에서만 보이지만, 그 수명은 전체 프로그램입니다.

| | // 정적 데이터 시연
#include
using namespace std;
class temp
{
private:
static int count; // 모든 객체에 대해 단 하나의 데이터 항목
public:
temp() { count++; } // 객체 생성 시 카운트 증가
int getcount() { return count; } // 카운트 반환
};
int main()
{
temp t1, t2, t3; // 세 개의 객체 생성
cout << “\nCount is    “ << t1.getcount( ); // 각 객체
cout << “\nCount is    “ << t2.getcount( ); // 동일한 값을 봄
cout << “\nCount is    “ << t3.getcount( ); // 카운트의 동일한 값
return 0;
} |

| | 위 프로그램의 출력은 다음과 같습니다: (정적일 경우)
Count is  3
Count is  3
Count is  3
위 프로그램의 출력 (자동일 경우)
Count is 1
Count is 1
Count is 1 |

13. 정적 멤버 함수

정적 멤버 변수와 마찬가지로 정적 멤버 함수도 가질 수 있습니다. 정적으로 선언된 멤버 함수는 다음과 같은 특성을 가집니다.

| | - 정적 함수는 동일한 클래스에 선언된 다른 정적 멤버(함수 또는 변수)만 접근할 수 있습니다.

  • 정적 멤버 함수는 다음과 같이 클래스 이름을 사용하여 호출할 수 있습니다:
    class-name :: function-name; |

| | // 정적 멤버 함수 시연
#include
using namespace std;
class test
{
int code ;
static int count; // 정적 멤버 변수
public:
void setcode() { code = ++count; }
void showcode() { cout << “객체 번호 :” << code << endl; }
static void showcount() // 정적 멤버 함수
{
cout << “카운트  :” << count << endl;
}
};
int test :: count;
int main()
{
test t1, t2;
t1.setcode();
t2.setcode();
test::showcount(); // 정적 함수 접근
test t3;
t3.setcode();
test::showcount();
t1.showcode();
t2.showcode();
t3.showcode();
return 0;
} |

14. 친구 함수

| | |

비공식 멤버는 클래스 외부에서 접근할 수 없습니다. 즉, 비멤버 함수는 클래스의 비공식 데이터에 접근할 수 없습니다. 그러나 두 클래스가 특정 함수를 공유하고 싶어하는 상황이 있을 수 있습니다. 이는 친구 함수를 통해 간단하게 달성됩니다.

| | 친구 함수는 특정 특성을 가집니다: - 그것은 친구로 선언된 클래스의 범위에 있지 않습니다.

  • 클래스의 범위에 없기 때문에 클래스의 객체를 사용하여 호출할 수 없습니다. 일반 함수처럼 객체의 도움 없이 호출할 수 있습니다.
  • 멤버 함수와 달리 멤버 이름에 직접 접근할 수 없으며 각 멤버 이름에 대해 객체 이름과 점 멤버 연산자를 사용해야 합니다.
  • 의미에 영향을 주지 않고 클래스의 public 또는 private 부분에 선언할 수 있습니다.
  • 일반적으로 객체를 인수로 가집니다. |

| | // 친구 함수 시연
#include
using namespace std;
class test
{
int a;
int b;
public:
void setvalue() { a = 25; b = 40; }
friend float sum(test s); // FRIEND 선언
};
float sum(test s)
{
return float (s.a + s.b ) / 2.0; // s.a & s.b는 클래스 test의 비공식 멤버이지만 친구 함수에 의해 접근 가능
}
int main()
{
test x;
x.setvalue();
cout << “평균 값  = “ << sum(x) << endl;
return 0;
} |

친구 함수를 두 클래스 간의 다리로 구현하기 위한 또 다른 예제입니다.
다음 프로그램은 두 클래스의 두 객체와 두 클래스에 친숙한 함수를 생성합니다.
이 예제에서 친구 함수는 두 클래스의 데이터 멤버에 접근할 수 있으며 두 클래스의 데이터 멤버 중 가장 큰 값을 계산합니다.

| | #include
using namespace std;
class second;
class first
{
int a;
public:
first(int temp) { a = temp; }
friend void max(first, second);
};
class second
{
int b;
public:
second(int temp) { b = temp; }
friend void max(first, second);
};
void max(first f, second s)
{
if ( f.a > s.b ) // 첫 번째, 두 번째 데이터 멤버 모두
cout << “최대 “<<  f.a; // 친구 최대 함수로 접근 가능
else
cout << “최대 “<< s.b;
}
int main()
{
first f(20);
second s(30);
max(f, s);
return 0;
} |

참조: Turbo C++의 객체 지향 프로그래밍: 로버트 라포르

Share: X/Twitter LinkedIn

새 게시물을 받은 편지함에서 받기

스팸은 없습니다. 언제든지 구독 해지 가능합니다.