💙ref.
1. 객체 지향
1.1. 객체
- 객체: 변수들과 참고 자료들로 이루어진 소프트웨어 덩어리
- 객체에 포함된 변수 및 함수: 인스턴스 변수, 인스턴스 메소드
- 추상화: 현실 세계의 개념을 컴퓨터가 처리할 수 있도록 적절한 형태로 변환
- 캡슐화: 외부에서 변수 값 변경 불가, 메소드를 통해 간접 접근
- 객체 내부 동작 원리를 몰라도 해당 기능 사용 가능
1.2. 클래스
- 객체의 설계도!
- 어떠한 기능에 대한 틀(내부 구현 x)
- 클래스를 이용해서 만들어진 객체를 인스턴스라고 부름
- 클래스 구성 요소: 멤버 변수, 멤버 함수
private
로 정의된 요소들은 객체 외부에서 접근 불가능- 일반적으로 멤버 변수는
private
, 멤버 함수는public
으로 정의(캡슐화)
- 일반적으로 멤버 변수는
2. 클래스 다루기
2.1. 함수 오버로딩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
void print(int x) { std::cout << "int : " << x << std::endl; }
void print(char x) { std::cout << "char : " << x << std::endl; }
void print(double x) { std::cout << "double : " << x << std::endl; }
int main()
{
int a = 1;
char b = 'c';
double c = 3.2f;
print(a);
print(b);
print(c);
return 0;
}
// 실행 결과
// int : 1
// char : c
// double : 3.2
-
함수명이 같더라도 인자가 다르면 다른 함수로 판단
-
컴파일러가 적합한 인자를 가지는 함수를 찾아 호출
-
정확히 일치하는 타입이 없을 경우 형변환 수행
대상 변환 결과 char
,unsigned char
,short
int
unsigned short
int
,unsigned int
float
double
enum
int
-
형변환을 수행해도 일치하는 타입의 함수가 없을 경우
대상 변환 결과 임의의 숫자(numeric) 다른 숫자 타입 enum
임의의 숫자 0
포인터, 숫자 포인터 void
포인터 -
유사한 타입의 함수를 찾을 수 없을 경우
-
모호하다(ambiguous)고 판단해 오류 발생
eg)
error C2668: 'print' : ambiguous call to overloaded function
-
-
-
2.2. 생성자(constructor)
- 객체 생성 시 자동으로 호출되는 함수
- 클래스의 멤버 변수 초기화
- 클래스 사용에 필요한 설정값 정의
- 생성자 정의:
/* 클래스 이름 */ (/* 인자 */) {}
- 생성자 유형
- 암시적 방법(implicit):
Date day(2011, 3, 1);
- 명시적 방법(explicit):
Date day = Date(2012, 3, 1);
- 암시적 방법(implicit):
2.2.1 디폴트 생성자 (Default Constructor)
- 생성자를 명시적으로 정의하지 않았을 경우 컴파일러가 자동으로 추가해주는 생성자
- 개발자가 생성자를 정의하지 않아도 생성자가 호출됨!
- 단, 컴파일러가 생성했으므로 아무런 동작도 하지 않음
- 디폴트 생성자 사용자 정의 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
class Date {
int year_;
int month_; // 1 부터 12 까지.
int day_; // 1 부터 31 까지.
public:
void ShowDate();
Date() // 디폴트 생성자 정의
{
year_ = 2012;
month_ = 7;
day_ = 12;
}
};
C++ 11부터 디폴트 생성자를 명시적으로 정의할 수 있다!
1
2
3
4
5
class Test
{
public:
Test() = default; // 디폴트 생성자 정의 명령어
};
- 생성자 선언 뒤에
= default
를 붙여 디폴트 생성자 명시
2.2.2 생성자 오버로딩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
class Date {
int year_;
int month_; // 1 부터 12 까지.
int day_; // 1 부터 31 까지.
public:
void ShowDate();
Date()
{
std::cout << "기본 생성자 호출!" << std::endl;
year_ = 2012;
month_ = 7;
day_ = 12;
}
Date(int year, int month, int day)
{
std::cout << "인자 3 개인 생성자 호출!" << std::endl;
year_ = year;
month_ = month;
day_ = day;
}
};
- 인자를 다르게 한 여러 개의 생성자를 정의해 오버로딩 구현 가능
3. explicit / mutable
3.1. explicit
- 원하지 않는 암시적 변환을 할 수 없도록 컴파일러에게 명시
예제1 - 암시적 변환 방지
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class MyString
{
char* string_content; // 문자열 데이터를 가리키는 포인터
int string_length; // 문자열 길이
int memory_capacity;
public:
// capacity 만큼 미리 할당함. (explicit 키워드에 주목)
explicit MyString(int capacity);
// 문자열로 부터 생성
MyString(const char* str);
// 복사 생성자
MyString(const MyString& str);
~MyString();
int length() const;
int capacity() const;
};
// .. (생략) ..
void DoSomethingWithString(MyString s)
{
// Do something...
}
int main()
{
DoSomethingWithString(3); // ????
}
// 컴파일 오류
// test5.cc:56:3: error: no matching function for call to 'DoSomethingWithString'
// DoSomethingWithString(3); // ????
// ^~~~~~~~~~~~~~~~~~~~~
// test5.cc:51:6: note: candidate function not viable: no known conversion from 'int' to 'MyString' for 1st argument
// void DoSomethingWithString(MyString s) {
// ^
// 1 error generated.
int capacity
를 받는 생성자가explicit
으로 명시MyString
생성자를explicit
으로 선언해 해당 생성자를 이용한 암시적 변환 방지int
에서MyString
으로 변환 불가능
예제2 -복사 생성자 호출 방지
1
2
MyString s = "abc"; // MyString s("abc")
MyString s = 5; // MyString s(5)
- 컴파일러가 적절한 생성자를 호출
s
에 값을 대입한다는 의미
1
2
MyString s(5); // 허용
MyString s = 5; // 컴파일 오류!
explicit
으로MyString(int capacity)
를 설정할 경우 컴파일 오류 발생(복사 생성자 형태 호출 방지)
3.2. mutable
멤버 변수를 mutable
로 선언할 경우 const
함수의 멤버 변수를 변경할 수 있다.
- 멤버 함수를
const
로 선언하는 이유: 해당 함수는 객체 내부 상태에 영향을 주지 않는다는 의미 표현- eg) 읽기 작업을 수행하는 함수
- 서버의 경우 메모리에 캐시를 만들어 자주 요청되는 데이터를 빠르게 조회
- 즉각 캐시를 갱신하기 위해
const
로 정의된 유저 서버 함수의Cache
를mutable
로 선언해 관리
- 즉각 캐시를 갱신하기 위해
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
class A
{
mutable int data_; // mutable로 선언한 data_
public:
A(int data) : data_(data) {}
void DoSomething(int x) const
{
data_ = x;
}
void PrintData() const { std::cout << "data: " << data_ << std::endl; }
};
int main()
{
A a(10);
a.DoSomething(3);
a.PrintData();
}
mutable
로 선언한data_
의 값이const
함수 내부에서 변경됨mutable
로 선언하지 않을 경우const
함수의 멤버 변수에 값 대입 불가능
Leave a comment