-
C++ Primer CH7. Classesc++ 2024. 1. 21. 16:16
Defining a Member Function outside the Class
클래스 내에 선언된 모양과 똑같이 정의내려야 한다.
일단 컴파일러가 함수 이름을 보면, 나머지 코드는 클래스 내부에 있는 것처럼 해석한다. 따라서 멤버변수 사용할 수 있다.
double Sales_data::avg_price() const { if (units_sold) return revenue/units_sold; else return 0; }
return *this; → 인스턴스 참조자가 리턴됨
7.14 Constructors
default constructor
- Sales_data total;
- 이런식으로 선언만 해주는 것처럼 보이는데, default constructor가 호출된다.
- 인자 아무것도 안 넣는 경우의 constructor가 호출되고, 구현해놓지 않아도 컴파일러가 알아서 구현해서 호출해준다.
- 아무런 constructor도 정의해놓지 않았을 경우에만 자동생성된다.
- synthesize 못해줄 수도 있다
- 멤버로 클래스를 가지는데 해당 클래스의 default constructor가 없을 경우
defining the Sales_data Constructors
struct Sales_data { Sales_data() = default; Sales_data(string &s) : boookNo(s) {} Sales_data(string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p*n) {} Sales_data(istream &); //...
7.2 Access Control and Encapsulation
access specifier을 안쓰면 외부에서 그냥 멤버변수에 막 접근할 수 있기 때문에 캡슐화가 이루어지지 않은 상태다.
private specifier를 사용해서 캡슐화를 한다.
캡슐화된 클래스
#include <string> using namespace std; class Sales_data { public: Sales_data() = default; // 생성자1 Sales_data(const string &s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p*n) {} // 생성자2 string isbn() const { return bookNo; } // 멤버함수 정의 Sales_data &combine(const Sales_data&); // 멤버함수 선언 private: double avg_price() const { return units_sold ? revenue/units_sold : 0; } string bookNo; unsigned units_sold = 0; double revenue = 0.0; };
- class와 struct의 차이
- -> access specifier을 쓸 수 있나 없나 차이
7.2.1 Friends
외부의 함수나 클래스가 private인 멤버에 접근할 수 있도록 만들어줌
class 내부에 friend로 만들고 싶은 함수나 클래스를 선언해주면 됨.
class Sales_data { friend Sales_data add(const Sales_data&, const Sales_data&); friend istream &read(istream&, Sales_data&); friend ostream &print(ostream&, const Sales_data&); ... };
- 캡슐화의 장점
- -> 유저코드가 객체 내부 상태를 변형시키지 못하도록 함
- -> 인터페이스를 통해 클래스에 접촉하기 때문에 유저레벨 코드 변경에 자유롭다.
7.3 Additional Class Features
typedef 정의내리기
class Screen { public: typedef std::string::size_type pos; Screen()=default; // neededbecauseScreenhasanotherconstructor // cursor initialized to 0 by its in-class initializer Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht * wd, c) { } char get() const // get the character at the cursor {returncontents[cursor];} // implicitlyinline inline char get(pos ht, pos wd) const; // explicitly inline Screen &move(posr,posc); private: pos cursor = 0; pos height = 0, width = 0; std::string contents; };
Making Members inline
클래스 내에 정의된 멤버함수는 자동으로 인라인 상태가 된다.
밖에서 정의할건데 인라인 하고싶으면 inline 붙이면 된다.
밖에서 정의할 때만 인라인 붙이는게 읽기 편하다.
Overloading Member Functions
멤버함수도 오버로딩이 된다.
mutable Data Members
함수 선언할 때 return쪽에 const 붙으면, 내부 로직에서 변수의 상태가 변하지 않음을 보장하는데, 멤버변수에 mutable 키워드를 붙여놨다면 저 const가 해당 변수에 대해서 무시된다.
Initializers for Data Members of Class Type
멤버변수를 또다른 클래스들의 인스턴스들로 초기화시키는 법
class Window_mgr { private: std::vector<Screen> screens{Screen(24, 80, ' ')}; };
7.3.2 Functions That Return *this
class Screen { public: Screen &set(char); Screen &set(pos, pos, char); // 다른 멤버들 }; inline Screen &Screen::set(char c) { contents[cursor] = c; return *this; } inline Screen &Screen::set(pos r, pos col, char ch) { contents[r*width + col] = ch; return *this; } myScreen.move(4,0).set('#'); // 반환값인 *this는 오브젝트의 레퍼런스이기 때문에 체인호출 가능 Screen temp = myScreen.move(4,0); // 참조자가 temp에 Screen으로 복사됨 temp.set('#'); // 복사된 오브젝트에 접근하기 때문에 원본은 안바뀜
멤버변수,함수를 static으로 선언하면 이것들은 개별 오브젝트에 속하지 않게 된다. 따라서 내부에서 this도 못쓴다.
근데 오브젝트에서 해당 static에 접근할 수는 있어서 쓸 수 있다.
클래스 내의 일반 함수에서 static에 접근 가능하다
일반과 static의 차이점
- static은 생성자의 인자로 넣을 수 있음
- static은 선언시 자기클래스를 타입으로 가질 수 있음
'c++' 카테고리의 다른 글
C++ Primer CH9. Sequential Containers (1) 2024.01.21 C++ Primer CH8. The IO Library (0) 2024.01.21 C++ Primer CH6. Functions (0) 2024.01.21 C++ Primer CH4. Expressions (0) 2024.01.21 C++ Primer CH3. Strings, Vectors and Arrays (0) 2024.01.21 - Sales_data total;