◆OOP
- 프로그래머는 객체를 서술하는 데 필요한 데이터와, 사용자가 그 데이터를 다루는 방법에 대해서 생각하면서, 사용자가 이해하는 방식대로 객체에 초점을 맞춘다.
◆데이터 은닉(data hiding)
- 프로그램이 직접 데이터에 접근하지 못하게 차단하는 것
◆캡슐화(encapsulation)
●세부적인 구현들을 따로 결합하여 추상화화 분리하는 것이다.
- 데이터 은닉은 캡슐화의 한 예이다.
- 또 다른 예는 클래스 함수들의 정의를 클래스 선언과 독립된 파일에 넣는 것이다.
◆클래스
◆클래스 설계
- public 인터페이스와 세부적인 구현을 private에 분리하려고 노력한다.
- public 인터페이스는 설계의 추상화를 나타낸다.
◆클래스의 접근제한자
●private
- 클래스 내부에서만 접근할 수 있다.
- 클래스 객체에 대한 디폴트 접근 제어이다.
●public
- 어디에서든 접근할 수 있다.
- 구조체 객체에 대한 디폴트 접근 데어이다.
◆클래스 멤버 메서드의 정의
- 함수머리를 추가하여 일반 함수처럼 정의한다.
●함수머리(function heading)
- 함수가 어느 클래스에 속하는지 나타내기 위해서 사용 범위 결정 연산자(::)를 사용한다.
void Cat::cry();
- cry()가 클래스 사용 범위(class scope)를 가지고 있다.
- ※해당 함수가 클래스 안에서 쓰일때는, 함수 머리 없이 사용할 수 있다.
◆클래스 멤버 메서드 정의하는 법
- 메서드 정의는 클래스 선언과 같은 파일에 또는 독립된 파일에 넣을 수 있다.
- 선언은 헤더에서, 정의는 메서드를 사용하는 파일에서 해주는것을 권장한다.
◆인라인 메서드
- 클래스 선언 안에 정의를 가지고 있는 모든 함수는 자동으로 인라인 함수가 된다.
- 원한다면 함수를 정의할 때 inline이라는 제한자를 앞에 붙여서 외부에 멤버 함수를 인라인 선언할 수 있다.
class Cat{
void cry();
}
inline void Cat::cry(){
cout<<"Meow";
}
- ※코드 수정 규칙(rewrite rule)에 따르면, 클래스 선언 안에 메서드를 정의하는 것은 그 메서드 정의를 원형으로 대체하고, 클래스 선언 바로 뒤에 그 메서드 정의를 인라인 함수로 다시 작성하는 것과 같다.
●각각 선언한 클래스를 통해 메서드를 호출하는 것은 각각의 멤버 변수를 인자로 같은 하나의 멤버 메서드를 호출하여 두개의 객체에 적용한다는 것이다.
●멤버 함수를 호출한다는 말은, 다른 OOP 언어에서 메시지를 보낸다는 말과 같은 뜻이다.
◆클라이언트-서버 모델(OOP)
- 클라이언트는 클래스를 사용하는 프로그램이고, 서버는 그것을 필요호 하는 프로그램들이 사용할 수 있는 리소스이다.
- 이것은, 클라이언트의 행동에 예측할 수 없는 영향을 일으키는 변화를 서버에 가져오지 않고, 클라이언트와 서버의 기능을 프로그래머들이 서로 독립적으로 개선하는 것을 허용한다.
◆플래그를 고정 소수점 표기를 사용하기 위해 cout 개체 안에 플래그를 세팅하는 코드.
std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
◆cout으로 소수점 이하 3 자리까지 보여 주도록 하는 코드
std::cout.precision(3);
◆원본 클래그를 저장하고 리셋하는 코드
std::ios_base::fmtflags orig = std::cout.setf(std::ios_base::fixed);
std::cout.setf(orig, std::ios_base::floatfield);
◆클래스의 생성자
- C++는 클래스 객체를 표준 데이터형을 사용하듯이 사용할 수 있게 만드는 것이 목표인데, 멤버들이 private로 정의되기 때문에 초기화를 실현하는데에 어려움을 겪는다.
- 일반적으로, 모든 객체는 그것을 생성할 때 초기화하는 것이 가장 바람직함으로 C++는 새로운 객체를 생성하고 그들의 데이터 멤버에 값을 대입해 주는 클래스 생성자(class constructor)라는 특별한 멤버 함수를 제공한다.
- 생성자의 이름은 클래스의 이름과 같다.
- 생성자는 리턴값이 없는데도 불구하고 void형으로 선언하지 않는다.(데이터 형을 선언하지 않는다.)
//생성자 정의
Cat::Cat(const char & name,int & age){
catName=name;
catAge=age;
}
◆멤버 이름과 매개변수 이름
- 멤버 이름과 매개변수의 이름은 구분을 위해서 달라야한다.
- 일반적으로 매개변수에 m_ 접두사를 사용하거나 _ 접미사를 사용한다.
class Cat{
char * name;
int * age;
Cat::Cat(const char & m_name,int & age_ ){
name = m_name;
age = age_;
}
}
◆생성자 사용하기
●C++는 생성자를 이용하여 객체를 초기화하는 두 가지 방법을 제공한다.
1. 생성자를 명시적으로 호출
Cat black = Cat("black", 1);
2. 생성자를 암시적으로 호출
Cat black("black", 1);
+ new를 사용해 생성자를 사용하는 방법
Cat *gray = new Cat("gray", 2);
◆디폴트 생성자(default constructor)
●명시적인 초기화 값을 제공하지 않을 때 객체를 생성하는 데 사용하는 생성자이다.
Cat red; //디폴트 생성자를 사용한다.
Cat::Cat(){}을 호출한 것과 같다.
- ※사용자가 어떠한 생성자도 정의하지 않을 경우에만 컴파일러가 디폴트 생성자를 제공함으로, 생성자를 만들었다면 디폴트 생성자의 책임이 사용자에게 넘어옴으로 유의해야 한다.
●디폴트 생성자를 정의하는 두가지 방법
1. 기존의 생성자에 있는 모든 매개변수에 디폴트 값을 제공
Cat(const char & name = "NONAME", int & age = 0);
2. 함수 오버로딩을 사용하여 매개변수가 없는 또 하나의 생성자를 정의
Cat(){}
- ※단, 사용자는 하나의 디폴트 생성자만 가질 수 있다.
- ※디폴트 생성자를 암시적으로 호출할 때는 괄호를 사용하면 안된다.
●아래는 black()[메서드,함수]가 Cat객체를 리턴하는 함수임을 나타내는 것이다.
Cat black();
◆파괴자(destructor)
- 객체의 수명이 끝나는 시점에서, 프로그램은 파괴자라는 특별함 멤버함수를 자동으로 호출하여 메모리를 해제한다.
- 파괴자는 앞에 틸데(~)가 붙은 클래스 이름으로부터 만들어진다.
Cat::~Cat(){}
- 파괴자는 파괴하는 것 외에 할일이 없으면 하는일이 없는 코드로 작성한다.
- new를 사용해 객체를 생성한다면, 이는 힙 메모리 또는 자유 기억 공간에 저장되므로, 그것의 메모리를 해제하기 위해 delete를 사용할 때 파괴자가 자동으로 호출된다.
●어떤 작업을 수행하기 위해 임시적인 객체를 생성할 수 있다. 이때 파괴자는 임시적인 객체를 삭제하는데 사용된다.
Cat gray; //암시적 선언
gray = Cat("gray", 2);
- 오른쪽의 Cat("gray", 2)은 rvalue임으로 gray에 복사를 하고 파괴자를 호출한다.
★객체의 값을 초기화로도 설정할 수 있고 대입으로도 설정할 수 있다면, 초기화를 사용하라, 그것이 더 효율적이다.
◆리스트 초기화
- C++는 중괄호 안의 값들과 생성자의 매개변수들을 매칭시키는 것을 제공한다.
Cat black = {"black",1};
Cat white{"white"}; //디폴트 나이 0으로 초기화
◆const 멤버 함수
- 클래스에 const를 작성하여도 내부 멤버 변수는 const가 아님으로 변할 수 있다.
- 이것을 해결하는 방법은 함수 괄호 뒤에 const를 집어 넣는것이다. (이것이 const 멤버 함수이다.)
- const 멤버 함수는 호출 객체를 변경할 수 없다.
void Cat::cry() const;
◆매개변수가 하나인 생성자 초기화 방법
class Cat{
Cat(int age){};
}
//1.
Cat first = Cat(1);
//2.
Cat second(2);
//3.
Cat third = 3;
◆this
- 클래스 내부에서 자신은 반환(표현)하기 위해 사용한다.
- 생성자와 파괴자를 포함한 각각의 멤버 함수는 하나의 this 포인터를 가진다.
- this 포인터의 특별한 특징은 호출한 객체를 지시하는 것이다.
- 호출한 객체를 메서드가 전체적으로 참조할 필요가 있을 경우에는 *this를 사용할 수 있다.
- 함수의 매개변수 괄호 뒤에 const 제한자를 사용하면, this 포인터를 const로 제한한다.
- 그러한 경우에는, this 포인터를 사용하여 그 객체의 값을 변경할 수 없다.
◆객체 배열
- 객체 배열은 표준 데이터형의 배열을 선언하는 것과 완전히 동일한 방법으로 선언한다.
- 생성자를 사용하여 배열 원소들을 초기화할 수 있다.
Cat cats[3]={
Cat("black",1),
Cat("white",0),
Cat("red")
}
◆클래스 사용 범위
- 클래스는 상수를 선언할 수 없다.
●해결법 2가지
1. 클래스 안에 열거체를 선언할 수 있다.
class Bakery{
private:
enum {Months=12}
double consts[Months];
}
2. static을 사용하여 상수를 정의한다.
class Bakery{
private:
static const int Months = 12;
double consts[Months];
}
- 이는 객체 안이 아닌 다른 정적 변수들과 함께 저장되는 Months라는 하나의 상수를 생성한다.
◆범위가 정해진 열거(전통적인 열거의 문제점)
- 두개의 다른 enum 정의로부터 온 열거자는 충돌한다는 문제점이 있다.
//충돌!
enum chicken {S,M,L,XL};
enum T_shirt {S,M,L,XL};
●해결법 2가지
1. 열거자에게 클래스 범위를 갖게 한다.
enum class chicken {S,M,L,XL};
enum class T_shirt {S,M,L,XL};
2. 클래스 대신에 struct 키워드를 사용한다.
enum struct chicken {S,M,L,XL};
enum struct T_shirt {S,M,L,XL};
- 두 경우 모두 사용시 enum이름을 사용해야 한다.
단, 사용시 enum 이름을 사용해야 한다.
chicken choice = chicken::XL;
T_shirt coolTshirt = T_shirt::XL;
- ※범위가 지정된 열거는 int형으로의 암시적 전환이 이루어지지 않는다.
- ※그러나 꼭 필요하다면 명시적 형 변환을 할 수 있다.
int chicken = int(chicken::S); //0
◆추상화 데이터형
- 클래스를 잘성할때 데이터(멤버)를 추상화 해서 만들것!
'C++ > C++' 카테고리의 다른 글
12. 클래스와 동적 메모리 대입, +추가 필요 (0) | 2023.07.25 |
---|---|
11. 클래스의 활용 (0) | 2023.07.19 |
9. 메모리 모델과 이름 공간 (0) | 2023.07.14 |
8. 함수의 활용 ★ (0) | 2023.07.12 |
7. 함수 - C++의 프로그래밍 모듈 (0) | 2023.07.10 |