U E D R , A S I H C RSS

AcceleratedC++/Chapter13

1. Chapter 13 Using inheritance and dynamic binding

13μž₯μ—μ„œλŠ” 4μž₯μ—μ„œ λ§Œλ“€μ—ˆλ˜ 성적 계산 ν”„λ‘œκ·Έλž¨μ„ 학뢀생, λŒ€ν•™μ›μƒμ— λŒ€ν•΄μ„œ λ™μž‘ν•˜λ„λ‘ κΈ°λŠ₯을 ν™•μž₯ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ ν†΅ν•΄μ„œ 상속과 λ‹€ν˜•μ„±(동적바인딩)의 κ°œλ…μ„ λ°°μš΄λ‹€.
(9.6μ ˆμ— μžˆλŠ” 기쑴의 ν”„λ‘œκ·Έλž¨μ„ μ΄μš©ν•œλ‹€.)

1.1. 13.1 Inheritance

상속(inheritance)
λͺ‡ 가지 좔가사항을 μ œμ™Έν•˜λ©΄ ν•œν΄λž˜μŠ€μ™€ λ‹€λ₯Έ ν΄λž˜μŠ€κ°€ λ™μΌν•œ κ²½μš°κ°€ λ§Žλ‹€λŠ” 데에 μ°©μ•ˆν•΄μ„œ λ‚˜μ˜¨ κ°œλ…μ΄λ‹€.
이 ν”„λ‘œκ·Έλž¨μ˜ 경우 κΈ°μ‘΄ 객체와 λ‹€λ₯Έ 뢀뢄은 λ™μΌν•˜μ§€λ§Œ λŒ€ν•™μ›μƒμ˜ 성적을 λ‹€λ£¨λŠ” κ²½μš°μ—λŠ” λ…Όλ¬Έκ³Ό κ΄€λ ¨λœ μ μˆ˜κ°€ ν¬ν•¨λœλ‹€λŠ” 가정을 ν•˜κ³  λ§Œλ“€μ–΄μ§„λ‹€.

λŒ€ν•™μ›μƒκ³Ό ν•™λΆ€μƒμ˜ μ„±μ μ˜ 곡톡적 μš”μ†Œλ§Œμ„ ν‘œν˜„ν•œ Core Class
~cpp 
class Core {
public:
	Core();
	Core(std::istream&);
	std::string name() const;
	std::istream& read(std::istream&);
	double grade() const;
private:
	std::istream& read_common(std::istream&);
	std::string n;
	double midterm, final;
	std::vector<double> homework;
};

λŒ€ν•™μ›μƒμ— κ΄€λ ¨λœ 점을 μΆ”κ°€ν•œ Grad class
~cpp 
class Grad:public Core {	// κ΅¬ν˜„(implementation)의 일뢀가 μ•„λ‹Œ μΈν„°νŽ˜μ΄μŠ€(interface)의 μΌλΆ€λ‘œμ„œ μƒμ†λ°›λŠ”λ‹€λŠ” 것을 λ‚˜νƒ€λƒ„.
public:				// Core의 publicμš”μ†ŒλΌ κ·ΈλŒ€λ‘œ public μš”μ†Œλ‘œ λ°›λŠ”λ‹€.
	Grad();
	Grad(std::istream&);
	double grade() const;
	std::istream& read(std::istream&);
private:
	double thesis;		// λ…Όλ¬Έκ΄€λ ¨ μ μˆ˜λΌ μ €μž₯ν•˜λŠ” λ©€λ²„λ³€μˆ˜
}
Grad ν΄λž˜μŠ€λŠ” Core둜 λΆ€ν„° νŒŒμƒλ˜μ—ˆλ‹€(Derived from), μƒμ†λ°›μ•˜λ‹€(inherits from), ν˜Ήμ€ CoreλŠ” Grad의 base class 이닀 λΌλŠ” ν‘œν˜„μ„ μ‚¬μš©ν•œλ‹€.
상속받은 ν΄λž˜μŠ€λŠ” κ·Έ λΆ€λͺ¨ν΄λž˜μŠ€μ˜ μƒμ„±μž, μ†Œλ©Έμž, λŒ€μž…μ—°μ‚°μžλΌ μ œμ™Έν•œ κ·Έμ™Έμ˜ λͺ¨λ“  클래슀의 μš”μ†ŒλΌ λ¬Όλ €λ°›λŠ”λ‹€.
λ˜ν•œ νŒŒμƒ ν΄λž˜μŠ€λŠ” λΆ€λͺ¨ 클래슀의 λ©”μ†Œλ“œλΌ μž¬μ •μ˜ ν•˜μ—¬μ„œ μžμ‹ μ—κ²Œ λ§žλ„λ‘ μˆ˜μ •ν•˜μ—¬ λ™μž‘ν•˜λŠ” 것을 ν—ˆμš©ν•œλ‹€.

1.1.1. 13.1.1 λ³΄ν˜Έμ •μ±…(protection)에 λŒ€ν•΄μ„œ λ‹€μ‹œ μ‚΄νŽ΄λ³΄κΈ°

private 보호 λ ˆμ΄λΈ”λ‘œ μ§€μ •λœ λ©€λ²„λŠ” κ·Έ 클래슀 자체, friend ν•¨μˆ˜λΌ ν†΅ν•΄μ„œλ§Œ μ§μ ‘μ μœΌλ‘œ 접근이 κ°€λŠ₯ν•˜λ‹€. 이 경우 μƒμ†λœ ν΄λž˜μŠ€μ—μ„œλŠ” λΆ€λͺ¨ 클래슀의 private λ©€λ²„λ‘œμ˜ 접근이 ν•„μš”ν•œλ° μ΄λŸ΄λ•Œ protectedλΌλŠ” ν‚€μ›Œλ“œλΌ μ‚¬μš©ν•˜λ©΄ μ’‹λ‹€.
protected λ ˆμ΄λΈ”λ‘œ μ§€μ •λœ 멀버듀은 μžμ‹ ν΄λž˜μŠ€μ—μ„œ 직접적인 접근이 κ°€λŠ₯λ‹€. κ·ΈλŸ¬λ‚˜ 클래슀의 μ™ΈλΆ€μ—μ„œλŠ” 접근이 μ•ˆλ˜κΈ° λ•Œλ¬Έμ— μΊ‘μŠν™”μ˜ μž₯점을 μœ μ§€μ‹œν‚¬ 수 μžˆλ‹€.
~cpp 
class Core {
public:
	Core();
	Core(std::istream&);
	std::string name() const;
	double grade() const;
	std::istream& read(std::istream&);
protected:
	std::istream& read_common(std::istream&);
	double midterm, final;
	std::vector<double>homework;
private:
	std::string n;
 

1.1.2. 13.1.2 μ—°μ‚°

κ΅¬ν˜„ν•΄μ•Όν•  λΆ€λΆ„.
Core, Grad의 μƒμ„±μž 4가지. 각기의 ν΄λž˜μŠ€μ— 따라 λ‹€λ₯΄κ²Œ ν–‰λ™ν•˜κ²Œ λ˜λŠ” read, grade ν•¨μˆ˜. Core 클래슀의 name, read-common ν•¨μˆ˜.
Core class의 κΈ°λ³Έ κ΅¬ν˜„
~cpp 
string Core::name() const { return n; }

double Core::grade() const {
	return ::grade(midterm. final, homework);
}

istream& Core::read_common(istream& in) {
	in>>n>>midterm>>final;
	return in;
}

istream& Core::read(istream& in) {
	read_common(in);
	read_hw(in, homework);
	return in;
}
 
Grad::read ν•¨μˆ˜μ˜ μ˜€λ²„λ‘œλ”©
~cpp 
istream& Grad::read(istream& in) {
	read_common(in);
	in >> thesis;
	read_hw(in, homework);
	return in;
}
 
μƒκΈ°μ˜ ν΄λž˜μŠ€λŠ” Grad의 멀버 ν•¨μˆ˜λ‘œ λΆ€λͺ¨ 클래슀의 read_common, read_hw의 ν•¨μˆ˜λΌ κ·ΈλŒ€λ‘œ μƒμ†λ°›μ•˜λ‹€λŠ” 것을 κ°€μ •ν•œλ‹€.
μ΄λΌ λͺ…μ‹œμ μœΌλ‘œ ν‘œν˜„ν•˜λ©΄ λ‹€μŒκ³Ό 같이 ν‘œν˜„ν•  수 μžˆλ‹€.

~cpp 
istream& Grad::read(istream& in) {
	Core::read_common(in);
	in >> thesis;	// thesisλŠ” Coreκ°€ μ•„λ‹ˆλΌ Grad의 멀버 λ³€μˆ˜μ΄λ€λ‘œ λ²”μœ„ 지정 μ—°μ‚°μžλΌ μ‚¬μš©ν•΄μ„œλŠ” μ•ˆλœλ‹€.
	Core::read_hw(in, Core::homework);
	return in;
}
 

thesisκ°€ 적용된 μ μˆ˜λΌ λ¦¬ν„΄ν•˜λŠ” Grad::grade() ν•¨μˆ˜
~cpp 
double Grad::grade() const {
	return min(Core::grade(), thesis);		// min()은 <algorithm>에 μ •μ˜λœ ν•¨μˆ˜μ΄λ‹€.
}
 
Core::grade()λΌ μ‚¬μš©ν•˜μ§€ μ•Šκ³  grade()λΌ μ‚¬μš©ν•˜κ²Œ 되면 Grade:grade()λΌμž¬κ·€μ μœΌλ‘œ ν˜ΈμΆœν•˜μ—¬ μ–΄λ–€ κ²°κ³ΌλΌ λ¦¬ν„΄ν• μ§€ μ˜ˆμƒν•˜μ§€ λͺ»ν•œλ‹€.

1.1.3. 13.1.2 상속 및 μƒμ„±μž

νŒŒμƒ 클래슀의 생성단계
* 전체 객체에 λŒ€ν•œ 곡간을 ν• λ‹Ή
* κΈ°λ³Έ 클래슀 μƒμ„±μž 호좜, 기본클래슀 곡간 μ΄ˆκΈ°ν™”
* μƒμ„±μžμ˜ 초기μ„μ •μž( ): { 사이에 μ‘΄μž¬ν•˜λŠ” 것듀 )λΌ μ΄μš©ν•΄μ„œ νŒŒμƒν΄λž˜μŠ€μ˜ 멀버 μ΄ˆκΈ°ν™”
* νŒŒμƒ 클래슀의 μƒμ„±μžμ˜ λ³Έμ²΄λΌ μ‹€ν–‰ν•œλ‹€.

~cpp 
class Core {
public:
	Core():midterm(0), final(0) {}
	Core(std::istream& is) { read(is); }
};

class Grad:public Core {
public:
	Grad():thesis(0) {}
	Grad(std::istream& is) { read(is); }
};
 
Grad의 μƒμ„±μžλŠ” Core의 μƒμ„±μžκ°€ midterm, final을 μ΄ˆκΈ°ν™” ν•œλ‹€λŠ” κ°€μ •ν•˜μ—μ„œ thesisλ§Œμ„ μ΄ˆκΈ°ν™”ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ΄ˆκΈ°ν™”λŠ” μ•”λ¬΅μ μœΌλ‘œ ν–‰ν•˜μ—¬μ§„λ‹€.
λ§ˆμ°¬κ°€μ§€λ‘œ Grad(std::istream&)을 μ΄μš©ν•΄μ„œ κ°μ²΄λΌ μ΄ˆκΈ°ν™”ν•  λ•Œμ—λ„ λΆ€λͺ¨ 객체의 λ””ν΄νŠΈ μƒμ„±μžλ‘œ λ¨Όμ € 기쑴의 뢀뢄을 μ΄ˆκΈ°ν™”ν•˜κ³ , Grad::read(istream&)λΌ ν†΅ν•΄μ„œ 각 μš”μ†Œμ˜ 값을 μ΄ˆκΈ°ν™”ν•˜κ²Œ λœλ‹€.

1.2. 13.2 Polymorphism and virtual functions

~cpp 
bool compare(const Core& c1, const Core& c2) {
	return c1.name() < c2.name();
}
μƒκΈ°μ˜ ν•¨μˆ˜λŠ” sort에 μ˜ν•΄μ„œ 각 μš”μ†Œμ˜ νŒλ‹¨μ‹μœΌλ‘œ μ‚¬μš©λ˜λŠ” ν•¨μˆ˜μ΄λ‹€. 이 ν•¨μˆ˜λŠ” λΆ€λͺ¨κ°μ²΄μΈ Core 객체 λΏλ§Œμ•„λ‹ˆλΌ, μžμ‹ 객체인 Grad객체도 λŒ€μž…ν•˜μ—¬ μ‚¬μš©ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
~cpp 
Grad g(cin);
Core c(cin);
compare(g, c);		// Grad, Coreλ ˆμ½”λ“œλΌ λΉ„κ΅ν•œλ‹€.
Grad ν΄λž˜μŠ€κ°€ μ‚¬μš©κ°€λŠ₯ν•œ 이유
비둝 ν•¨μˆ˜κ°€ μš”κ΅¬ν•˜λŠ” μΈμžκ°’μ€ Core 클래슀 μ΄μ§€λ§Œ GradλŠ” CoreλΌ κΈ°λ°˜μœΌλ‘œν•΄μ„œ νŒŒμƒλœ 클래슀이기 λ•Œλ¬Έμ— 이 경우 name();λΌ ν˜ΈμΆœν•˜κ²Œ 되면 g 객체의 Core::name() 뢀뢄이 ν˜ΈμΆœλœλ‹€.
λ‹€μ‹œ λ§ν•΄μ„œ Gradκ°€ Core의 μžμ‹ 클래슀 이λ€λ‘œ Gradκ°μ²΄λΌ ν†΅ν•΄μ„œ Core클래슀의 ν•¨μˆ˜λΌ λ°”μΈλ”©μ‹œμΌœ μ‚¬μš©ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€λŠ” λœ»μ΄λ‹€. (λŒ€μ‹ μ— 이 ν•¨μˆ˜μ˜ μ•ˆμ—μ„œλŠ” Grad의 Core 의 μš”μ†Œλ“€λ§Œμ„ μ·¨ν•œλ‹€.)

1.2.1. 13.2.1 객체의 νƒ€μž…μ„ λͺ¨λ₯΄λŠ” μƒνƒœμ—μ„œ 값을 μ–»κΈ°

λ§Œμ•½ 이름이 μ•„λ‹ˆλΌ μ΅œμ’… 성적을 가지고 λΉ„κ΅λΌ ν•˜κ³  싢을 κ²½μš°λΌ λ‹€λ£¨κ²Œ λœλ‹€.

grade와 μœ μ‚¬ν•œ κΈ°λŠ₯을 ν•˜λŠ” compare_grade ν•¨μˆ˜
~cpp 
bool compare_grade(const Core& c1, const Core& c2) {
	return c1.grade() < c2.grade();
}
 
λ§Œμ•½ μœ„ ν•¨μˆ˜μ— 인자둜 μ „λ‹¬λœ 객체가 Grad객체라면 κ·Έ κ°μ²΄μ—μ„œ ν˜ΈμΆœλ˜λŠ” gradeλŠ” Core::grade() μ΄μ–΄μ„œλŠ” μ•ˆλœλ‹€. κ·Έλ ‡κ²Œ 호좜될 경우 λ…Όλ¬Έ μ μˆ˜κ°€ μ μš©λ˜μ§€ μ•Šμ€ μ„±μ λΌ λ¦¬ν„΄ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. λ”°λΌμ„œ Grad::grade() 의 ν•¨μˆ˜λΌ ν˜ΈμΆœν•΄μ•Ό ν•  것이닀.
이런 행동을 ν•¨μˆ˜μ— μ „λ‹¬λ˜λŠ” ν˜„μž¬μ˜ μΈμžκ°€ 무엇이냐에 λ”°λΌμ„œ λ‹€λ₯΄κ²Œ κ²°μ •λ˜μ–΄μ•Ό ν•˜λ€λ‘œ μ‹€ν–‰μ‹œ(runtime)에 κ²°μ •λ˜μ–΄μ•Ό ν•  것이닀.

동적바인딩을 μœ„ν•œ virtualν‚€μ›Œλ“œ
~cpp 
class Core {
public:
	virtual double grade() const;	// virtual 이 좔가됨.
};
 
virtual ν‚€μ›Œλ“œλ‘œ μ§€μ •λœ ν•¨μˆ˜λŠ” μ‹€μ œλ‘œ ν•¨μˆ˜κ°€ ν˜ΈμΆœλ λ•Œ κ·Έ 객체의 이름 λ²”μœ„μ— μ‘΄μž¬ν•˜λŠ” ν•¨μˆ˜λΌ ν˜ΈμΆœν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.

1.2.2. 13.2.2 동적 바인딩(Dynamic binding)

동적 바인딩이 μˆ˜ν–‰λ˜κΈ° μœ„ν•΄μ„œλŠ” μ „λ‹¬μΈμžλ‘œ μ „λ‹¬λœ 값이 포인터, 참쑰이어야 κ°€λŠ₯ν•˜λ‹€.
~cpp 
bool compare_grades(Core c1, Core c2) {
	return c1.grade() < c2.grade();
}
 
μƒκΈ°μ˜ 경우 Grad κ°μ²΄λΌ μΈμžλ‘œ 전달할 경우 Grad객체의 Core객체의 μš”μ†Œλ§Œ λ³΅μ‚¬λ˜μ–΄ ν•¨μˆ˜μ˜ 인자둜 μ „λ‹¬λ˜κΈ° λ•Œλ¬Έμ— Core::grade()κ°€ ν˜ΈμΆœλ˜μ–΄μ„œ 정적바인딩(static binding)이 μˆ˜ν–‰λœλ‹€.

λ§Œμ•½ μΌλ°˜ν˜•μ˜ λ³€μˆ˜λ‘œ virtualν•¨μˆ˜λΌ ν˜ΈμΆœν•˜λ©΄ 객체가 항상 ν•œκ°€μ§€ νƒ€μž…μœΌλ‘œλ§Œ μ‘΄μž¬ν•˜κΈ° λ•Œλ¬Έμ— 정적바인딩이 λœλ‹€. κ·ΈλŸ¬λ‚˜ 포인터, μ°Έμ‘°ν˜•μ˜ 경우 μ΄λ ‡κ²Œ ν• λ•Œμ—λŠ” λ™μ λ°”μΈλ”©μœΌλ‘œ λ™μž‘ν•˜κ²Œ λœλ‹€. ν¬μΈν„°μ˜ ν˜•κ³Ό μ‹€μ œ 포인터가 κ°€λ¦¬ν‚€λŠ” λ°μ΄ν„°ν˜•μ΄ λ‹€λ₯ΈμΌμ΄ 생기기 λ•Œλ¬Έμ΄λ‹€. λ”°λΌμ„œ 이 경우 virtual λ©€λ²„ν•¨μˆ˜λŠ” λŸ°νƒ€μž„μ— λ™μ μœΌλ‘œ 바인딩 λœλ‹€.
λŒ€μ‹  virtual ν‚€μ›Œλ“œλ‘œ μ§€μ •λœ ν•¨μˆ˜λŠ” νŒŒμƒ ν΄λž˜μŠ€μ—μ„œ λ°˜λ“œμ‹œ μž¬μ •μ˜ λ˜μ–΄μ•Όν•œλ‹€λŠ” νŠΉμ§•μ΄ μžˆλ‹€.

λ‹€ν˜•μ„±(polymorphism)
κΈ°λ³Έ νƒ€μž…μ— λŒ€ν•œ ν¬μΈν„°λ‚˜ λ ˆνΌλŸ°μŠ€κ°€ ν•„μš”ν•œ 곳에 νŒŒμƒ νƒ€μž…μ„ μ‚¬μš©ν•  수 μžˆλ‹€λŠ” κ°œλ…. ν•˜λ‚˜μ˜ νƒ€μž…μ„ ν†΅ν•΄μ„œ μ—¬λŸ¬ ν•¨μˆ˜λ“€ 쀑 ν•˜λ‚˜λΌ μ„ νƒν•˜μ—¬ ν˜ΈμΆœν•  수 μžˆλ‹€.

1.2.3. 13.2.2 μš”μ•½


~cpp 
#ifndef GUARD_Core_h
#define GUARD_Core_h

#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

class Core {
public:
	Core(): midterm(0), final(0) { }
	Core(std::istream& is) { read(is); }

	std::string name() const;

	// as defined in 13.1.2/230
	virtual std::istream& read(std::istream&);		// virtual ν‚€μ›Œλ“œλ‘œ μ •μ˜λœ ν•¨μˆ˜λŠ” λ°˜λ“œμ‹œ μž¬μ •μ˜λ˜μ–΄μ•Όν•œλ‹€.
	virtual double grade() const;

protected:
	// accessible to derived classes
	std::istream& read_common(std::istream&);
	double midterm, final;
	std::vector<double> homework;

private:
	// accessible only to `Core'
	std::string n;
};

class Grad: public Core {
public:
	Grad(): thesis(0) { }
	Grad(std::istream& is) { read(is); }

	// as defined in 13.1.2/230; Note: `grade' and `read' are `virtual' by inheritance
	double grade() const;
	std::istream& read(std::istream&);
private:
	double thesis;
};

bool compare(const Core&, const Core&);
#endif
 

1.3. 13.3 Using inheritance to solve our problem

λ§Œλ“€μ–΄μ§„ ν΄λž˜μŠ€λΌ μ΄μš©ν•΄μ„œ 성적을 μž…λ ₯λ°›κ³  λ³΄κ³ μ„œλΌ μΆœλ ₯ν•˜λŠ” ν”„λ‘œκ·Έλž¨ (Core)
~cpp 
int main() {
	vector<Core> students;
	Core record;		// Core의 μΌλ°˜ν˜•
	string::size_type maxlen = 0;

	while(record.read(cin)) {
		maxlen = max(maxlen, record.name().size());
		students.push_back(record);
	}

	sort(students.begin(), students.end(), compare);

	for (vector<Core>::size_type i = 0; i != students.size(); ++i) {
		cout<<students[i].name()
			<<string(maxlen + 1 - students[i].name.size(), ' ');
		try {
			double final_grade = students[i].grade();
			streamsize prec = cout.precision();
			cout<<setprecision(3)<<final_grade
				<<setprecision(prec)<<endl;
		} catch (domain_error e) {
			cout<<e.what()<<endl;
		}
	}
	return 0;
}

λ§Œλ“€μ–΄μ§„ ν΄λž˜μŠ€λΌ μ΄μš©ν•΄μ„œ 성적을 μž…λ ₯λ°›κ³  λ³΄κ³ μ„œλΌ μΆœλ ₯ν•˜λŠ” ν”„λ‘œκ·Έλž¨ (Grad)
~cpp 
int main() {
	vector<Grad> students;
	Grad record;		// Grad의 μΌλ°˜ν˜•
	string::size_type maxlen = 0;

	while(record.read(cin)) {
		maxlen = max(maxlen, record.name().size());
		students.push_back(record);
	}

	sort(students.begin(), students.end(), compare);

	for (vector<Grad>::size_type i = 0; i != students.size(); ++i) {
		cout<<students[i].name()
			<<string(maxlen + 1 - students[i].name.size(), ' ');
		try {
			double final_grade = students[i].grade();
			streamsize prec = cout.precision();
			cout<<setprecision(3)<<final_grade
				<<setprecision(prec)<<endl;
		} catch (domain_error e) {
			cout<<e.what()<<endl;
		}
	}
	return 0;
}
μž…λ ₯을 λ°›λŠ” recordκ°€ μΌλ°˜ν˜•μ΄κΈ° λ•Œλ¬Έμ— μœ„μ— 2개의 ν”„λ‘œκ·Έλž¨μ€ 각기 Core, Grad에 λŒ€ν•΄μ„œ μ •μ μœΌλ‘œ λ°”μΈλ”©λœλ‹€.
μ΄λ ‡κ²Œ ν”„λ‘œκ·Έλž¨μ΄ μž‘μ„±λ˜λ©΄ λ™μΌν•œ κΈ°λŠ₯을 ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μžλ£Œν˜•μ— λ”°λΌμ„œ 2κ°€μ§€λ‘œ λ”°λ‘œ μž‘μ„±ν•΄μ•Όν•œλ‹€.

λ‹¨μΌν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜κΈ°μœ„ν•΄μ„œ νƒ€μž… μ˜μ‘΄μ„±μ„ μ œκ±°ν•΄μ•Όν•  λΆ€λΆ„
* 읽어듀일 μš”μ†Œλ“€μ„ μ €μž₯ν•˜λŠ” vector의 μ •μ˜
* λ ˆμ½”λ“œλΌ μ½μ–΄λ“€μΌ μž„μ‹œ 지역 λ³€μˆ˜μ˜ μ •μ˜
* read ν•¨μˆ˜
* grade ν•¨μˆ˜
λ§ˆμ§€λ§‰ 2가지 λ¬Έμ œλŠ” virtual둜 μ •μ˜λœ λ©€λ²„ν•¨μˆ˜λΌ ν†΅ν•΄μ„œ ν•΄κ²°. 처음의 2κ°€μ§€λΌ ν•΄κ²°ν•˜λŠ” 방법은 2가지가 μ‘΄μž¬ν•˜λ©° 13.3~13.4μ ˆμ— κ±Έμ³μ„œ μ„λͺ…ν•œλ‹€.

1.3.1. 13.3.1 μ•Œμ§€ λͺ»ν•˜λŠ”(κ°€μƒμ μœΌλ‘œ) νƒ€μž…μ— λŒ€ν•œ μ»¨ν…Œμ΄λ„ˆ

μ•žμ˜ μ˜ˆμ—μ„œμ²˜λŸΌ vector<Core>의 μ»¨ν…Œμ΄λ„ˆλΌ μ„μ •ν•˜κ²Œ 되면 μ»¨ν…Œμ΄λ„ˆ μ•ˆμ— μ €μž₯λ˜λŠ” 객체가 Core의 객체가 되λ€λ‘œ μ •μ μœΌλ‘œ λ°”μΈλ”©λœλ‹€. μ΄λΌ ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ” vector<Core*>λΌ ν†΅ν•΄μ„œ κ°μ²΄λΌ λ™μ μœΌλ‘œ ν• λ‹Ήν•˜κ³  κ΄€λ¦¬ν•˜λ„λ‘ ν•˜λ©΄, μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μ˜ κ°μ²΄λΌ μ €μž₯ν•˜λŠ” 것도 κ°€λŠ₯ν•˜κ³  ν”„λ‘œκ·Έλž¨μ˜ λ‹€λ₯Έ λΆ€λΆ„μ—μ„œ λ‹€ν˜•μ„±μ˜ 이점을 μ΄μš©ν•˜λŠ” 것도 κ°€λŠ₯ν•˜λ‹€.
~cpp 
int main() {
	vector<Core*> students;

	Core* record;
	while (record->read(cin)) {
	//...
	}
}
 
μœ„μ˜ ν”„λ‘œκ·Έλž¨μ€ ν• λ‹Ήλ˜μ§€ μ•Šμ€ Core 곡간에 값을 λŒ€μž…ν•˜λ €ν•˜κΈ° λ•Œλ¬Έμ— μ—λŸ¬λΌ λ°œμƒμ‹œν‚¨λ‹€. ν”„λ‘œκ·Έλž˜λ¨Έκ°€ 객체에 ν•„μš”ν•œ 곡간을 직접관리. μ½μ–΄λ“€μ΄λŠ” λ ˆμ½”λ“œμ˜ μ’…λ₯˜λΌ νŒλ‹¨ν•΄μ•Όν•¨.

ν¬μΈν„°λ‘œ 이루어진 κ°μ²΄λΌ λΉ„κ΅ν•˜κΈ° μœ„ν•΄μ„œ μž‘μ„±ν•œ ν•¨μˆ˜
~cpp  
bool compare_Core_ptrs(const Core* cp1, const Core* cp2) {
	return compare(*cp1, *cp2);
}
 
μΈμžλΌ μ „λ‹¬ν•˜λ©΄μ„œ μƒκΈ°λŠ” λͺ¨ν˜Έν•¨μ„ ν”Όν•˜κΈ° μœ„ν•΄μ„œ compare λΌλŠ” μ΄λ¦„λŒ€μ‹ μ— compare_Core_ptrsλΌ μ‚¬μš©ν•˜μ—¬ μ»΄νŒŒμΌλŸ¬κ°€ λͺ…μ‹œμ μœΌλ‘œ 이 ν•¨μˆ˜λΌ μ‚¬μš©ν•˜λ„λ‘ ν•œλ‹€.

~cpp 
// main_core.cpp
#include <vector>
#include <string>
#include <algorithm>
#include <iomanip>

#include <ios>

#include <iostream>
#include <stdexcept>

#include "Core.h"

using std::cout;
using std::cin;
using std::domain_error;
using std::endl;
using std::setprecision;
using std::setw;
using std::streamsize;
using std::sort;
using std::string;
using std::vector;

using std::max;

// this code almost works; see 13.3.2/242
int main()
{
	vector<Core*> students;         // store pointers, not objects
	Core* record;                   // temporary must be a pointer as well
	char ch;
	string::size_type maxlen = 0;

	// read and store the data
	while (cin >> ch) {
		if (ch == 'U')
			record = new Core;      // allocate a `Core' object
		else
			record = new Grad;      // allocate a `Grad' object
		record->read(cin);          // `virtual' call
		maxlen = max(maxlen, record->name().size());// dereference
		students.push_back(record);
	}

	// pass the version of `compare' that works on pointers
	sort(students.begin(), students.end(), compare_Core_ptrs);

	// write the names and grades
	for (vector<Core*>::size_type i = 0;
	     i != students.size(); ++i) {
		// `students[i]' is a pointer that we dereference to call the functions
		cout << students[i]->name()
		     << string(maxlen + 1 - students[i]->name().size(), ' ');
		try {
			double final_grade = students[i]->grade();
			streamsize prec = cout.precision();
			cout << setprecision(3) << final_grade
			     << setprecision(prec) << endl;

		} catch (domain_error e) {
			cout << e.what() << endl;
		}
		delete students[i];        // free the object allocated when reading
	}
	return 0;
}
 
μž…λ ₯κ³Ό 좜λ ₯의 각 λΆ€λΆ„μ—μ„œ 그리고 μ»¨ν…Œμ΄λ„ˆμ˜ μš”μ†ŒλΌ μ‚¬μš©ν• λ•Œ ν¬μΈν„°λΌ μ΄μš©ν•¨μœΌλ‘œν•΄μ„œ ν”„λ‘œκ·Έλž¨μ΄ 동적바인딩을 μ΄μš©ν•΄μ„œ μƒλ‹Ήνžˆ 간결해진 것을 확인할 수 μžˆλ‹€.

1.3.2. 13.3.2 가상 μ†Œλ©Έμž(virtual destructor)

상기와 같은 κ΅¬μ‘°μ—μ„œλŠ” studentsi의 νƒ€μž…μ΄ Core* 이기 λ•Œλ¬Έμ— λ©”λͺ¨λ¦¬ ν•΄μ œμ‹œμ— Coreλ²„μ „μ˜ μ†Œλ©Έμžκ°€ 호좜되고 Grad 뢀뢄은 ν•΄μ œλ˜μ§€ μ•ŠλŠ”λ‹€.
μ†Œλ©Έμž μ—­μ‹œλ„ virtual ν•¨μˆ˜λ‘œ λ§Œλ“€μ–΄μ„œ λŒ€μƒ νƒ€μž…μ— 따라 λ‹€λ₯Έ λ™μž‘μ„±μ„ 보μž₯ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
~cpp 
class Core {
public:
	virtual ~Core() { }
	//이전과 동일
};
 
상기와 같이 빈 μ†Œλ©ΈμžλΌ μ‚¬μš©ν•˜λŠ” 것은 ν”ν•œ κ²½μš°μ΄λ‹€. κΈ°λ³Έ νƒ€μž…μ˜ μ†Œλ©ΈμžλΌ virtual 둜 λ§Œλ“¦μœΌλ‘œμ„œ νŒŒμƒ ν΄λž˜μŠ€μ—μ„œ λ°œμƒν•˜λŠ” 기타 μš”μ†Œλ“€μ„ ν•΄μ œν•΄μ•Όν•  κ²½μš°κ°€ 많기 λ•Œλ¬Έμ΄λ‹€.

1.4. 13.4 A simple handle class

상기와 같은 λ°©μ‹μœΌλ‘œ ν¬μΈν„°λΌ μ΄μš©ν•΄μ„œ ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜κ²Œ 되면 ν”„λ‘œκ·Έλž˜λ¨Έκ°€ λ©”λͺ¨λ¦¬λΌ μ§μ ‘μ μœΌλ‘œ κ΄€λ¦¬λΌ ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έμ— μ—¬λŸ¬κ°€μ§€ λ²„κ·ΈλΌ λ§Œλ“œλŠ” λ¬Έμ œμ μ„ 가지고 μžˆλ‹€.

ν•Έλ“€ 클래슀(handle class)
νŠΉμ • ν˜•μ˜ ν¬μΈν„°λΌ μΊ‘μŠν™”μ‹œν‚¨ μΈν„°νŽ˜μ΄μŠ€λΌ μ œκ³΅ν•΄μ„œ, ν”„λ‘œκ·Έλž˜λ¨Έμ—κ²Œ 포인터가 보이지 μ•Šλ„λ‘ ν•˜λŠ” 방법을 μ œκ³΅ν•œλ‹€.

~cpp 
//Student_info.h
#ifndef GUARD_Student_info_h
#define GUARD_Student_info_h

#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include "Core.h"

class Student_info {
public:
	// constructors and copy control
	Student_info(): cp(0) { }
	Student_info(std::istream& is): cp(0) { read(is); }
	Student_info(const Student_info&);
	Student_info& operator=(const Student_info&);
	~Student_info() { delete cp; }

	// operations
	std::istream& read(std::istream&);

	std::string name() const {
		if (cp) return cp->name();
		else throw std::runtime_error("uninitialized Student");
	}
	double grade() const {
		if (cp) return cp->grade();
		else throw std::runtime_error("uninitialized Student");
	}

	static bool compare(const Student_info& s1,		
	                    const Student_info& s2) {		// 정적 멀버 ν•¨μˆ˜μ˜ μ„ μ–Έ
		return s1.name() < s2.name();
	}

private:
	Core* cp;
};
#endif
 
Core*λΌ Student_infoλΌ ν†΅ν•΄μ„œ Wrapping μ‹œν‚΄μœΌλ‘œμ¨ ν”„λ‘œκ·Έλž˜λ¨ΈλŠ” μ‹€μ œλ‘œλ₯΄ Student_infoκ°€ 2가지 μ’…λ₯˜μ˜ κ°μ²΄λΌ λ‹€λ£° 수 μžˆμ§€λ§Œ μ‹€μ œμ˜ λ‚΄λΆ€ κ΅¬ν˜„μ€ μ•Œμ§€ λͺ»ν•˜κ²Œ λœλ‹€.
μ •μ λ©€λ²„ν•¨μˆ˜(static member fuction)
일반 멀버 ν•¨μˆ˜μ™€λŠ” 달리 κ·Έ 클래슀 νƒ€μž…μ˜ 객체에 λŒ€ν•΄ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 것이 μ•„λ‹ˆκ³ , 클래슀 μ•ˆμ—μ„œλŠ” 클래슀 객체의 정적 데이터 λ©€λ²„λ§Œμ„ λ‹€λ£¨λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
μž₯μ μœΌλ‘œλŠ” μž„μ˜ λ²”μœ„λΌ κ·Έ 클래슀의 λ²”μœ„λ§ŒνΌμ„ 가지기 λ•Œλ¬Έμ— 클래슀 λ‚΄λΆ€μ—μ„œ μ‚¬μš©λ λ•Œ ::compare와 ν˜Όλ™λ  μ—Όλ €κ°€ μ—†λ‹€λŠ” 것이닀.

1.4.1. 13.4.1 ν•Έλ“€ 읽기


~cpp 
istream& Student_info::read(istream& is) {
	delete cp;		// μ–Έμ–΄μ μœΌλ‘œ λ„ν¬μΈν„°λΌ ν•΄μ œν•˜λŠ” 것은 λ¬Έμ œκ°€ μ—†μœΌλ€λ‘œ μ²΄ν¬ν•˜λŠ” μ½”λ“œλΌ λ„£μ§€ μ•Šμ•„λ„ λœλ‹€.
	char ch;
	is>>ch;

	if(ch == 'U') {
		cp = new Core(is);
	} else {
		cp = new Grad(is);
	}

	return is;
}
 
μš°μ„ μ€ 첫번째 μΈμžλΌ λ°›μ•„μ„œ 생성할 객체의 νƒ€μž…μ„ κ²°μ •ν•˜κ³ , κ²°μ •λœ νƒ€μž…μ˜ κ°μ²΄λΌ μƒμ„±μ‹œν‚¨λ‹€.

1.4.2. 13.4.2 ν•Έλ“€ 객체 볡사

ν˜„μž¬ μƒνƒœμ˜ ν΄λž˜μŠ€λ‘œλŠ” λ³΅μ‚¬μƒμ„±μžκ°€ ν•„μš”ν•œ κ³³μ—μ„œ κ³Όμ—° cp에 ν• λ‹Ήλœ 객체가 Grad인지 CoreμΈμ§€λΌ ν™•μΈν•  방법이 μ—†λ‹€.
μ΄λΌ ν•΄κ²°ν•˜λŠ” 것은 볡사 μƒμ„±μžλΌ virtual 둜 ν• λ‹Ήν•˜κ³  μ΄λŸ¬ν•œ 일을 μ»΄νŒŒμΌλŸ¬μ—κ²Œ μœ„μž„μ‹œν‚€λŠ” 방법이닀.
~cpp 
class Core {
	friend class Student_info;
protected:
	virtual Core* clone() const { return new Core(*this); }
};

class Grad {
protected:
	Grad* clone() const { return new Grad(*this); }		// 본래 virtual ν•¨μˆ˜μ—μ„œλŠ” κΈ°λ³Έν΄λž˜μŠ€μ™€ νŒŒμƒν΄λž˜μŠ€μ—μ„œ
								// μ˜€λ²„λ‘œλ“œν•œλŠ ν•¨μˆ˜μ˜ νŒŒλΌλ©”ν„° λͺ…μ„Έ, λ¦¬ν„΄ν˜•μ΄ λ™μΌν•΄μ•Όν•˜μ§€λ§Œ
								// ν¬μΈν„°ν˜•μΈ κ²½μš°μ—λŠ” νŒŒμƒ 클래슀의 ν¬μΈν„°λΌ μ‚¬μš©ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
};
 
friend class Student_info; λΌ μ‚¬μš©ν•¨μœΌλ‘œν•΄μ„œ Student_info의 λͺ¨λ“  λ©€λ²„ν•¨μˆ˜λŠ” Core의 protected, private에 μ ‘κ·Όν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
Student_info ν΄λž˜μŠ€μ—μ„œ Grad::clone()λΌ μ§μ ‘μ μœΌλ‘œ ν˜ΈμΆœν•˜λŠ” κ²½μš°κ°€ μ—†κΈ° λ•Œλ¬Έμ— friend둜 μ„ μ–Έν•˜μ§€ μ•Šμ•„λ„ λ¬΄κ΄€ν•˜λ‹€.

~cpp 
Student_info::Student_info(const Student_info& s) : cp(0) {
	if (s.cp) cp = s.cp->clone();
}

Student_info& Student_info::operator=(const Student_info& s) {
	if (&s != this) {
		delete cp;
		if (s.cp)
			cp = s.cp->clone();
		else
			cp = 0;
	{
	return *this;
}
 

1.5. 13.5 Using the handle class

~cpp 
//main_perfect.cpp
#include <algorithm>
#include <iomanip>

#include <ios>

#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include "Student_info.h"

using std::cin;
using std::cout;
using std::domain_error;
using std::endl;
using std::setprecision;
using std::setw;
using std::sort;
using std::streamsize;
using std::string;
using std::vector;

using std::max;

int main()
{
	vector<Student_info> students;
	Student_info record;
	string::size_type maxlen = 0;

	// read and store the data
	while (record.read(cin)) {
		maxlen = max(maxlen, record.name().size());
		students.push_back(record);
	}

	// alphabetize the student records
	sort(students.begin(), students.end(), Student_info::compare);

	// write the names and grades
	for (vector<Student_info>::size_type i = 0;
	     i != students.size(); ++i) {
		cout << students[i].name()
		     << string(maxlen + 1 - students[i].name().size(), ' ');
		try {
			double final_grade = students[i].grade();
			streamsize prec = cout.precision();
			cout << setprecision(3) << final_grade
			     << setprecision(prec) << endl;
		} catch (domain_error e) {
			cout << e.what() << endl;
		}
	}
	return 0;
}
μ „μ²΄μ μœΌλ‘œ μ‰¬μš΄ μ†ŒμŠ€μ΄λ€λ‘œ μƒλž΅, λͺ¨λ₯΄λ©΄ 책을 μ°Έμ‘°.

1.6. 13.6 Subtleties

1.6.1. 13.6.1 상속 및 μ»¨ν…Œμ΄λ„ˆ

vector<Core>κ°€ κ·Έ νŒŒμƒν˜•μ„ 담을 수 μ—†λ‹€λŠ” 것에 μœ μ˜ν•˜λΌ. (일견 될 것 처럼 λ³΄μ΄μ§€λ§Œ μ•ˆλœλ‹€)
~cpp 
 vector<Core> students;
 Grad g(cin);
 students.push_back(g);
 
μœ νš¨ν•œ ν‘œν˜„μ΄κΈ°λŠ” ν•˜μ§€λ§Œ g의 Coreν΄λž˜μŠ€μ—μ„œ μ •μ˜λœ λΆ€λΆ„ 만이 μ €μž₯이 λœλ‹€.
μ›ν•˜λŠ” λ°©μ‹λŒ€λ‘œ λ™μž‘ν•˜λŠ” 것인지 μ•„λ‹Œμ§€λŠ” ν”„λ‘œκ·Έλž˜λ¨Έμ˜ μ˜λ„μ— λ‹¬λ €μžˆλ‹€.

1.6.2. 13.6.2 μ–΄λ–€ ν•¨μˆ˜λΌ μ›ν•˜λ‚˜μš”?

λ§Œμ•½ λΆ€λͺ¨ ν΄λž˜μŠ€μ— μžˆλŠ” λ©”μ†Œλ“œμ™€ λ©”μ†Œλ“œ λͺ…은 κ°–μ§€λ§Œ νŒŒλΌλ©”ν„°λ‚˜ νƒ€μž…μ΄ 같이 μ•ŠμœΌλ©΄ λ©”μ†Œλ“œλŠ” μ™„μ „νžˆ λ‹€λ₯Έ ν•¨μˆ˜λ‘œ μΈμ‹λ˜μ–΄ μž‘λ™ν•œλ‹€.
~cpp 
 //λ§Œμ•½ r이 Core의 객체이고 Core::regrade(double)λŠ” 인자둜 받은 것을 final에 κΈ°λ‘ν•œλ‹€.  
 //Grad::regrade(double, double) 인자둜 λ°›μ€κ°’μœΌλ‘œ final, thesisλΌ ν• λ‹Ή
 r.regrade(100);		// μž‘λ™
 r.regrade(100, 100);	// 컴파일 였λ₯˜
 

~cpp 
 //λ§Œμ•½ r이 Grad의 객체이고 Core::regrade(double)λŠ” 인자둜 받은 것을 final에 κΈ°λ‘ν•œλ‹€.  
 //Grad::regrade(double, double) 인자둜 λ°›μ€κ°’μœΌλ‘œ final, thesisλΌ ν• λ‹Ή
 r.regrade(100);		// 컴파일 였λ₯˜. Grad::compare λΌ κΈ°λŒ€ν•˜κΈ° λ•Œλ¬Έμ— 이런 λ¬Έμ œκ°€ λ°œμƒν•œλ‹€. 
 r.Core::regrade(100);	// μž‘λ™. λ²”μœ„ μ—°μ‚°μžλΌ μ΄μš©ν•΄μ„œ λͺ…μ‹œμ μœΌλ‘œ ν˜ΈμΆœν•˜λŠ” 것은 ν—ˆμš©ν•œλ‹€.
 r.regrade(100, 100);	// μž‘λ™.
 

~cpp 
 virtual void Core::regrade(double d, double =0) { final = d; }
 
λ§Œμ•½ 이런 ν•¨μˆ˜λΌ virtual 둜 μ •μ˜ν•˜κ³  μ‹Άλ‹€λ©΄ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μΈμžλΌ λ””ν΄νŠΈ 인자둜 μ§€μ •ν•΄μ„œ λ§Œλ“€λ©΄ λœλ‹€.

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:22:24
Processing time 0.0540 sec