[따배씨++]Chapter8-2. 클래스

Date:     Updated:

카테고리:

태그:

인프런에 있는 홍정모님의 홍정모의 따라하며 배우는 C++ 강의를 듣고 정리한 내용입니다.
공부하는 식빵맘 님의 블로그를 참고했습니다.
learncpp 교재 내용을 참고했습니다.


🚆 클래스 코드와 헤더 파일

클래스를 포함한 Type은 단일 정의 규칙에서 일부 제외된다. 따라서 헤더 파일에 클래스를 정의해도 괜찮다.

📃 Date.h

#ifndef DATE_H
#define DATE_H

class Date
{
private:
	int _year = 1;
	int _month = 1;
	int _day = 1;

public:
	Date(int year, int month, int day);

	void setDate(int year, int month, int day);

	int getYear() { return _year; }
	int getMonth() { return _month; }
	int getDay() { return _day; }
};
#endif
  • 클래스 내부에 정의된 멤버 함수는 암시적으로 인라인 함수로 간주
    • constructor, getter와 같은 사소한 함수는 정의 안에 포함해도 괜찮음
  • 멤버 함수에 기본 값이 포함되어 있다면 클래스 정의(헤더 파일)에 선언


📃 Date.cpp

#include "Date.h"

// Date constructor
Date::Date(int year, int month, int day)
{
	setDate(year, month, day);
}

// Date member function
void Date::setDate(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}
  • 클래스의 멤버 함수들을 구현. Date:: 써줘야 함
  • 헤더파일과 이름이 같은 이유는 보기 편하라고
  • 표준 라이브러리의 경우 .cpp를 include하지 않는 특별한 케이스


🚆 Const 클래스

멤버 변수를 바꾸지 못하는 const class
const 클래스는 const 멤버 함수만 사용 가능 → 가능하면 전부 const 함수로 만들자

int getValue() const { return _value; }
  • const 위치는 파라미터 뒤, 본문 앞
  • const 멤버 함수는 객체 수정 불가
  • 내부에서 const 멤버 함수만 호출 가능
  • 보통 리턴타입도 const로 함
  • const 멤버 함수의 숨겨진 this 포인터들은 모두 const 클래스 반환
    • 따라서 const 멤버 함수는 non-const 참조를 반환할 수 없음
  • 클래스 정의 외부(.cpp 파일)에서 정의시 프로토 타입, 정의 모두에서 const 키워드 사용


Copy Constructor

일반적으로 변수가 함수의 파라미터로 넘어갈 때 복사되어 넘어간다. 이는 클래스가 넘어갈 때에도 마찬가지이다. 따라서 모든 클래스는 기본 생성자와 마찬가지로 복사 생성자가 숨어있다.

class Something
{
private:
	int _value = 0;

public:
	// constructor
	Something(int value_in)
		:_value{value_in}
	{}

	// copy constructor
	Something(const Something& st_in)
	{
		_value = st_in._value;
	}
};


const , non-const 오버로딩

const 여부도 오버로딩 가능하다.

class Something
{
private:
	string _value = "";

public:

	const string& getValue() const
	{
		cout << "const version" << endl;
		return _value;
	}

	string getValue()
	{
		cout << "non-const version" << endl;
		return _value;
	}
};
  • const 객체에서는 알아서 const version 호출
  • non-const 객체에서는 non-const version 호출


🚆 Static 멤버 변수

특정 instance와 상관 없는 멤버 변수

class Something
{
private:
	static int _value;
};

int Something::_value{ 1 };
  • static 멤버 변수 초기화는 접근 제어의 대상이 아님
    • private, protected 상관 없이 클래스 밖에서 초기화 가능
  • .cpp 파일에서 초기화
    • 헤더파일에서 초기화하면 여러 번 정의되어 링킹에러 발생
  • static constexpr, 몇몇 static const 타입은 클래스 내에서 초기화 가능


C++ 17부터 일반적인 static member variable도 클래스 내에서 초기화 가능

class Something
{
public:
	static inline int _value{ 5 };
};
  • 나 왜 에러나지..?? 구글링하면 다 된다고 하는데


🚆 Static 멤버 함수

특정 instance와 상관 없는 static 멤버 변수가 private인 경우 어떻게 접근할 수 있을까?

class Something
{
private:
	static int _value;
	
public:
	static int getValue() { return _value; }
};

int Something::_value{ 1 };

int main()
{
	cout << Something::getValue() << endl; // 1 출력
	return 0;
} 
  • static 멤버 함수는 this 포인터 사용할 수 없음
  • static 멤버 함수는 static 멤버 변수, static 멤버 함수만 호출 가능
  • static은 전역 멤버와 성질이 비슷하기 때문에 주의해서 사용해야 함


non-static 멤버 함수 포인터

멤버 변수는 각 객체들마다 메모리가 다르지만
멤버 함수는 객체마다 함수 메모리를 따로 갖는 방식이 아님 (&st.temp 컴파일 에러 뜨네..)

class Something
{
public:
	int temp() { return 1; }
};


int main()
{
	Something st;

	int(Something:: * fptr)() = &Something::temp;

	cout << (st.*fptr)() << endl;

	return 0;
}


Static 멤버 함수 포인터

int(*fptr)() = &Something::temp;

cout << fptr() << endl;
  • static 멤버 함수는 일반 함수 포인터로 취급


🚆 Friend 함수 및 클래스

클래스 외부 함수나 다른 클래스에게 private 멤버 접근 권한 부여

friend int getValue();
friend class Something
  • friend + 함수 프로토타입
  • friend class + 클래스 이름


다른 클래스의 특정 함수만 친구 맺기

class Display
{
public:
	void displayItem() {}
};

class Storage
{
private:
	int _value = 0;

public:
	friend void Display::displayItem();
};
  • friend 맺기 위해서는 전방 선언 해야 함 (Stroge 클래스가 먼저 선언되면 에러)
    • 근데 헤더파일 / cpp파일 나누면 실제로는 거의 문제가 되지 않음


🚆 Anonymous Objects - 익명 객체

한 번만 사용되는 임시 변수로 코드를 어지럽히는 것은 매우 비효율적이다.
익명 객체 의 사용은 코드를 아주 깔끔하게 유지하도록 도와준다.

void printValue(int value)
{
	cout << value << endl;
}

int main()
{
	printValue(5 + 3);

	return 0;
}

위 경우 5+3의 결과 8이 익명 객체에 배치된다. 그런 다음 이 익명 객체의 복사본이 printValue 함수의 파라미터로 전달된 다음 소멸된다.


Anonymous class objects

class Cents
{
private:
	int _cents = 0;

public:
	Cents(int cents) { _cents = cents; }

	int getCents() const { return _cents; }
};

Cents add(const Cents& c1, const Cents& c2)
{
	return Cents(c1.getCents() + c2.getCents());
}

int main()
{
	cout << add(Cents(6), Cents(8)).getCents() << endl;

	return 0;
}


🚆 Nested types in classes

클래스 내에서 다른 타입 중첩 가능 (타입 안에서 타입 정의)

class Fruit
{
public:
	enum FruitType
	{
		apple,
		banana,
		cherry
	};

private:
	FruitType _type{};
	
public:
	Fruit(FruitType type)
		:_type{ type }
	{}

	FruitType getType() const { return _type; }
};

int main()
{
	Fruit apple{ Fruit::apple };

	if (apple.getType() == Fruit::apple)
		cout << "I am an apple" << endl;
	else
		cout << "I am not an apple" << endl;

	return 0;
}
  • 적절한 접근 지정자 설정


🚆 코드 실행 시간 측정

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <chrono>
using namespace std;

class Timer
{
private:
	using clock_t = std::chrono::high_resolution_clock;
	using secont_t = std::chrono::duration<double, std::ratio<1>>;

	std::chrono::time_point<clock_t> start_time = clock_t::now();

public:
	void elapsed() // 경과
	{
		std::chrono::time_point<clock_t> end_time = clock_t::now();

		cout << std::chrono::duration_cast<secont_t>(end_time - start_time).count() << endl;
	}
};


int main()
{
	// 벡터 sorting 하는 예제

	random_device rnd_device;
	mt19937 mersenne_engine{ rnd_device() };

	vector<int> vec(100000);
	
	for (int i = 0; i < vec.size(); i++)
		vec[i] = i;

	std::shuffle(begin(vec), end(vec), mersenne_engine); 

	Timer timer;

	std::sort(begin(vec), end(vec));

	timer.elapsed(); // 0.0545231 출력

	return 0;
}
  • 실제 성능을 보기 위해서는 release모드 에서 재야 함
  • 환경에 따라 달라짐
    • 백그라운드 프로그램, 하드웨어 성능, …
    • 너무 민감하게 반응하지는 말기



맨 위로 이동하기

Cpp 카테고리 내 다른 글 보러가기

댓글 남기기