[따배씨++]Chapter8-2. 클래스
카테고리: Cpp
태그: Programming
인프런에 있는 홍정모님의 홍정모의 따라하며 배우는 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모드
에서 재야 함 - 환경에 따라 달라짐
- 백그라운드 프로그램, 하드웨어 성능, …
- 너무 민감하게 반응하지는 말기
댓글 남기기