※ LIG Nex1 The SSEN Embedded SW School에서 진행된 내용을 정리한 포스팅입니다.
객체 지향 프로그래밍 기법
함수 오버로딩
- 중복된 이름의 함수를 여러 개 정의 가능하다.
- 파라미터 개수, 타입을 다르게 정의해야 한다.
- 생성자, 메서드, 전역함수 모두 적용 가능하다.
함수 오버라이딩
- 상속받은 클래스의 멤버 함수를 재정의 한다.
- 다형성을 구현하는 데 사용된다.
상속
- 1차적인 목적: 코드 재사용성을 높이기 위함
- 객체지향의 핵심 다형성을 구현한다.
생성자/소멸자
- 생성자
- 반환 타입이 없고, 이름이 클래스와 동일한 멤버 함수
- 객체와 멤버 변수를 초기화 한다.
- 오버로딩이 가능하다.
- 객체 생성 시 한 번 호출된다.
- 기본 생성자를 명시적으로 제공하는 것이 좋다.
Point arr[3]; //Point의 기본생성자가 없는 경우 처리가 어렵다.
- private 생성자
- private 생성자는 singleton 디자인 패턴의 구현에 사용된다.
- 소멸자
- 반환 타입이 없다.
- 객체 소멸 시 호출된다.
- 클래스의 자원 해제 목적
- 생성자와 소멸자는 정의하지 않을 시 컴파일러가 default 생성자/소멸자를 제공해준다.
this
- 현재 객체의 주소를 갖는 포인터 변수
- runtime에서 사용하지 않고 클래스를 정의하는 부분에서 대치된다.
- 멤버 함수의 지역 변수와 멤버 변수의 이름이 같을 때 구분할 목적으로 사용한다.
static
- 객체의 사용 메모리 위치는 변수로 선언하면 스택, new로 생성하면 힙에 갖는다.
- static 멤버는 data영역에 저장된다.
- 멤버 변수로 생각하면 안 된다.
- 클래스의 변수라고 생각하자.
- 클래스를 공유하는 모든 객체가 접근할 수 있다.
- public인 경우 클래스 scope 연산자를 통해 바깥에서도 접근할 수 있다.
- ClassName::staticVar *= 42;
캡슐화
- 객체의 정보를 하나로 묶어주는 기능을 말한다.
- C에서는 한 객체에 대한 정보가 흩뿌려져 있다.
int score[3][5]; // [0]:num, [1~3]: KOR, ENG, MATH, [4]: total
int name[3];
float avg[3];
score의 total 순으로 정렬하라.하면 머리 깨진다.
- C++의 클래스를 활용하라
- 객체의 정보를 한 변수에 담고, 객체의 기능을 일관되게 제공할 수 있다.
정보은닉
- private을 통해 멤버 변수를 감싸고, 간접적으로 기능을 제공해야 한다.
- getter(), setter() 등
- 멤버 변수의 외부 접근을 허용하면 잘못된 값이 저장되는 문제가 발생할 수 있다.
- const를 잘 활용하라!
const 멤버 함수
- 함수 내에서 멤버 변수 값의 변경을 제한한다.
- const 함수는 const인 함수만 호출할 수 있다.
class ClassName {
private:
int a;
int b;
public:
void print_data() const{
cout << "(" << a << "," << b << ")\n";
}
}
초기화 리스트(initializer)
- initializer를 통해 초기화를 할 수 있다.
- 객체의 생성과 동시에 값이 초기화 되므로 const 또는 참조자(&) 변수를 초기화 시켜줄 수 있다.
class Point {
public:
Point()
: id(-1)
, x(0)
, y(0)
{}
Point(int id, int x, int y)
: id(id)
, x(x)
, y(y)
{}
void printPoint(void) {
cout << "x: " << x << ", y: " << y << endl;
}
private:
const int id;
int x;
int y;
};
int main()
{
Point a; // call default constructor
Point b(3,4); // call constructor(int, int)
a.printPoint();
b.printPoint();
return 0;
}
소멸자 예제
class Person {
char *name;
int age;
public:
Person(){}
Person(const char *name, int age)
: age(age)
{
int len = strlen(name) + 1;
this->name = new char[len];
strcpy(this->name, name);
}
void printInfo() const{
cout << "name: " << name << endl;
cout << "age: " << age << endl;
}
~Person() {
cout << "call destructor" << name << endl;
if (name)
delete[] name;
}
};
int main()
{
Person *group[3];
string input;
int age, i;
for (i = 0; i < 3; ++i) {
cout << "input Name> ";
cin >> input;
cout << "input age> ";
cin >> age;
group[i] = new Person(input.c_str(), age);
}
for (i = 0; i < 3; ++i) {
group[i]->printInfo();
delete group[i];
}
return 0;
}
self reference 반환 함수
Singleton 패턴 구현 시 유용하다.
- 반환되는 값이 값이 언제나 NULL이 아님을 보장한다.
- 레퍼런스 변수의 특징: NULL로 초기화할 수 없음.
// private static 변수
Singleton* Singleton::ptr = NULL;
// static으로 선언
Singleton& Singleton::getInstance(void)
{
if (ptr == NULL)
ptr = new Singleton();
return (*ptr);
}
// clean up 함수
void Singleton::cleanUp(void)
{
if (ptr != NULL)
delete ptr;
}
복사 생성자
- 대입 연산자뿐만 아니라 Initializer를 통한 복사 생성이 가능하다.
- 동일한 문장으로 해석한다.
// C style <-> C++ style
int num = 20;
int num(20);
int &ref = num;
int &ref(num);
- 클래스의 경우, 복사 생성자를 호출하여 복사된다.
- 컴파일러가 default 복사 생성자를 만들어준다.
- 얕은 복사를 하기 때문에 주소값만 복사된다.
- 객체 안에서 동적할당이 일어나는 경우 use after free 또는 double free error가 발생할 수 있다.
class Person {
/*code*/
Person(const Person& lhs)
: age(lhs.age)
{
this->name = new char[strlen(lhs.name) + 1];
strcpy(this->name, lhs.name);
}
/*code*/
};
int main()
{
Person p1("aaa", 12);
Person p2 = p1; // p2(p1);
p1.printInfo();
p2.printInfo();
return 0;
}
※ 질문, 개선점, 오류가 있다면 댓글로 남겨주세요 :)
'Language > C++' 카테고리의 다른 글
[TheSSEN/C++] 7. 상속 (0) | 2025.01.27 |
---|---|
[TheSSEN/C++] 6. static과 singleton 패턴 (0) | 2025.01.27 |
[TheSSEN/C++] 4. 객체 지향 프로그래밍 (0) | 2025.01.27 |
[TheSSEN/C++] 3. 클래스 (0) | 2025.01.27 |
[TheSSEN/C++] 2. 참조자(&) (0) | 2025.01.27 |