Cpp.07 Class and Object

oat·2024년 2월 13일
0

C++

목록 보기
8/10

Section 07

분할 컴파일

분할 컴파일

C++는 프로그램을 구성하는 함수들을 별개의 파일에 넣는 것을 권장한다
파일들을 개별적으로 분할하여서 컴파일한 후에 그것들을 하나의 최종 실행 프로그램으로 링크할 수 있다
=> 효율적으로 제어하기 위해 전처리 지시자 include 기능 제공

예제


먼저 MyStruct 구조체를 만들고, 그 구조체에 name과 age 변수를 넣었다

void display 함수의 원형을 선언하고

이 함수는 구조체 변수를 받아서 구조체 멤버 변수를 출력하는 기능을 가진다

Tip
함수의 매개변수로 전달된 것들을 단순히 출력한다는 등의 동작만 할 때는 앞에 const를 붙여 주는 것이 조금 더 바람직한 코딩이다

void display (const MyStruct&);

main 함수에서는 Oatmeal17로 구조체 변수를 만들었고, 그 구조체 변수 안에 oat와 17을 각각 name과 age에 할당되도록 초기화했다

그리고 display(Oatmeal17);을 호출하면서 함수는 종료된다

예제를 분할 컴파일하기

  1. header 파일
    - 함수 원형
    - #define이나 const를 사용하는 기호 상수
    - 구조체 선언
    - 클래스 선언
    - 템플릿 선언
    - 인라인 함수
    등의 내용이 포함될 수 있다

header 파일 관리에 대한 요구 사항!

header 파일을 여러 파일에 포함시킬 때 반드시 단 한번만 포함시켜야 한다

ex. 새로운 header 파일을 만들어서 그 header 파일 안에 기존의 struct.h를 include한다
-> 기존 소스 코드에 struct.h를 include 한 이후에 이 새로운 header 파일도 include한다
-> struct.h 파일이 총 두 번 include되기 때문에 에러가 발생하게 된다

이러한 불상사를 막기 위한 것이 if not define!

#ifndef (if not define)

#ifndef NAME
// code
#endif

ifndef 구문부터 endif 구문까지 NAME이라는 이름으로 묶이게 되는데,
이 NAME이란 이름이 #define에 의해서 정의되어 있지 않은 경우에만 이 구문을 처리하게 된다

if not defined 구문부터 end if에 있는 구문들을 기호상수화시키는 것!

이를 통해 컴파일러가 한 파일을 여러번 포함시키는 과정을 막을 수는 없지만,
처음으로 포함시킨 것을 제외한 나머지를 컴파일러가 포함하게 만들 수는 있다

예제

왼쪽에서 struct.h가 한번 include되면 그 다음에 struct.h를 갖고 있는 new.h가 include될 때,
if not defined 구문부터 end if에 사이에 있는 구문인 struct.h 전체를 무시한 채 실행되기 때문에 전처럼 오류가 발생하지 않는다


추상화와 클래스

추상화와 클래스

데이터형

메모리에 저장되는 데이터의 형태 (X)
그것을 대상으로 어떠한 연산을 수행할 수 있는가 (O)

추상화

어떠한 객체를 사실적으로 표현하는 것이 아니라, 공통된 특징을 간결한 방식으로 이해하기 쉽게 표현하는 것

클래스

추상화를 사용자 정의 데이터형으로 변환해주는 C++의 수단

클래스(class)란 무엇인가?

클래스는 두 부분으로 서술할 수 있다

1. 클래스 선언

2. 클래스 메소드 정의

예제

private / public

  • private
    비공개 멤버, 클래스 내에서만 접근 가능

  • public
    공개 멤버, 클래스 외부에서도 접근 가능

클래스의 멤버에 대한 접근을 제어하는 역할 수행

클래스가 가지고 있는 private 멤버들의 값을 변경하려면, 반드시 public에 선언되어 있는 함수들을 통해서 값을 변경해야 한다

ex. private의 share_val을 변경하기 위해서는 public의 update 함수를 사용해야 한다

=> public의 함수들은 프로그램이 private에 정의되어 있는 멤버 변수들의 값을 변경해 주거나, 그럴 수 있도록 이어 주는 다리 역할을 수행

데이터 은닉

프로그램이 반드시 public 멤버 함수들을 통해서 private 데이터에 직접 접근하지 못하게 차단하는 것
추상화의 한 예시라고 할 수 있다

직접적엔 데이터는 private로 선언하여 데이터를 은닉하자!

public의 멤버 함수 선언하기

className::funcName()

프로그램에게 이 클래스에 정의되어 있는 함수라는 것을 알려주기 위해 결정연산자(::)를 붙여줌으로써 선언할 수 있다
className::이 붙으면 함수가 클래스의 사용 범위에 결정된다고 프로그램이 받아들이게 된다

분할 컴파일 해보기


클래스 생성자와 파괴자

생성자와 파괴자

C++에서 기본적으로 제공해주는 함수 중 하나이기 때문에 없어도 프로그램의 실행에 문제가 되진 않는다

그러나 기본적으로 생각하는 데이터형이라 하면, 어떤 함수를 빌리는 것이 아니라 직관적으로 그 데이터의 값을 대입할 수 있어야 한다
ex. int a = 4;

그래서 C++가 내세우는 지향점 중 하나가 클래스 객체를 표준 데이터형을 사용하듯이 사용할 수 있게 만들어야 한다는 것이다

그래서 사용할 수 있는 것이 바로 생성자이다

생성자

리턴 값을 가질 수 없고, 선언된 데이터형을 가지지 않는다

이 두가지 방법으로 Stock이란 데이터형을 가진 변수를 선언할 수 있게 된다

그러나 이 경우, 생성자의 매개변수를 취하는 생성자를 만들었기 때문에 새로운 디폴트 생성자를 만들어야 한다

이 방법 외에도, 매개변수를 그대로 가져와서 디폴트 매개 변수를 선언해주는 방법 역시 동작한다

파괴자

객체를 생성하기 위해 생성자를 사용할 때, 프로그램은 객체의 수명이 다할 때까지 그 객체를 추적하는 책임을 맡게 된다
객체의 수명이 끝나는 시점에서 프로그램은 파괴자라는 특별한 멤버 함수를 자동으로 호출한다

파괴자는 특별한 이름을 가진다
바로 물결 표시(tilde) 틸데이다

Stock::~Stock()
{
	//code
}

클래스 이름 앞에 틸데가 붙은 클래스 이름은 파괴자로 명시된다
리턴 값을 가질 수 없고, 선언된 데이터형과 매개변수를 가지지 않는다

파괴자는 파괴하는 것 이와에 아무것도 하는 일이 없으므로 빈값으로 코딩될 수 있다
또한, 사용자가 명시적으로 코드 내부에서 파괴자를 호출할 수 없다

디폴트 생성자

아무런 매개변수 없이도 생성하는 생성자


this 포인터, 클래스 객체 배열

this 포인터

멤버 함수를 호출하는 데에 사용된 객체를 지시한다
포인터이기 때문에 주소를 나타내고 있으므로, 그 객체를 리턴하고자 한다면 *을 붙여야 한다

Stock Stock::topval(Stock& s) {
	if (s.share_val > shsare_val)
		retrun s;
	else return *this
}

s1.topval(s2).show();

매개변수 s2값이 크면 s2를 리턴하고, 호출한 객체인 s1값이 크면 this 포인터를 통해 s1을 리턴한다

클래스 객체 배열

같은 데이터형을 가지는 여러 개의 객체 = 배열

클래스 객체 배열의 선언 - 디폴트

Stock s[4];

각 배열의 원소마다 생성자에 정의되어 있던 값들을 취해주지 않았으므로 디폴트 생성자에 대입되어서 4개의 배열이 만들어지게 된다

클래스 객체 배열의 선언 - 값 부여

Stock s[4] = {
	Stock("A", 10, 1000),
    Stock("B", 20, 2000),
	Stock("C", 30, 3000),
	Stock("D", 40, 4000)
};

중괄호를 열고 각 배열의 원소에 해당하는 생성자를 불러줌으로써 그 값을 부여할 수 있다
각 배열의 원소는 콤마로 구분해 주어야 한다

여기서 배열이 생성되는 과정을 살펴보면,
1. 먼저 Stock s[4]를 통해서 4개의 배열 원소를 생성하고,
2. 그 배열 원소들에게 또다른 생성자를 할당해 주는 것이기 때문에

1번이 우선이기 때문에 클래스 객체 배열을 생성하기 위해서는 디폴트 생성자가 반드시 정의되어 있어야 한다

0개의 댓글