Stock 클래스 선언은
프로그램이 total_val에 직접 접근 할 수 없기 때문에, 데이터를 분석할 수 없다.
프로그램이 저장된 데이터에 대해 인지하게 하는 방법은 값을 리턴하는 메서드를 제공하는 것이다.
[이런 경우 보통 인라인 코드를 사용한다.]
class Stock
{
private:
...
double total_val;
...
public:
double total() const {return total_val;}
...
};
-> 프로그램이 데이터에 직접 접근을 가능하게
total_val을 읽기 전용 메모리로 만든다. 즉 total_val 메서드를 사용할 수 있다.
그 클래스는 total_val값을 구체적으로 재설정하는 메서드를 제공하지 않는다.
-> buy(), sell(), update()과 같은 다른 메서드는 total_val을 변경한다.
프로그램은 최대 가치를 지닌 주식이 무엇인지 알 수 있다.
두 개의 Stock 객체를 조사해 둘 중 더 큰 것에 대한 참조를 리턴하는 멤버 함수를 정의
1. 비교할 두 개의 객체를 그 멤버 함수에 어떤 방법으로 제공하나?
Stock stock1("NanoSmart", 20, 12.50); //구문 1
Stock stock2 = Stock("Boffo Objects", 2, 2.0); //구문 2
->stock1.topval() : 함수 호출은 stock1 객체의 데이터에 접근
->stock2.topval() : 메시지는 stock2 객체의 데이터에 접근
-> 매개변수를 참조로 전달하는 것이 효율적이므로
-> topval() 메서드가 const Stock &형의 매개변수를 사용
2. 그 메서드의 응답을 호출 프로그램에 어떻게 알리나?
-> 둘중 주식 가치가 더 큰 객체에 대한 참조를 리턴
const Stock& topval(const Stock & s) const;
const Stock& topval(const Stock & s) const;
: 한 객체에는 암시적으로 접근하고, 다른 한 객체에는 명시적으로 접근
두 객체 중의 하나에 대한 참조를 리턴
const Stock& topval(const Stock & s) const;
: 함수가 명시적으로 접근된 객체를 변경하지 않겠다.
const Stock& topval(const Stock & s) const;
: 함수가 암시적으로 접근된 객체를 변경하지 않겠다.
const Stock& topval(const Stock & s) const;
: 함수는 두 const 객체 중 하나를 리턴하므로 리턴형도 const이어야 한다.
top = stock1.topval(stock2);
//stock1에 암시적으로 접근하고 stock2에 명시적으로 접근
top = stock2.topval(stock1);
//stock1에 명시적으로 접근하고 stock2에 암시적으로 접근
topval()의 구현
const Stock& Stock::topval(const Stock & s) const
{
if (s.total_val > total_val)
return s; //매개변수로 전달받은 객체
else
return ?????? //메서드를 호출한 객체
}
-> s.total_val : 매개변수로 전달된 객체의 주식 총 가치
-> total_val : 메시지를 전달받은 객체의 주식 총 가치
s.total_val이 total_val보다 크지 않으면 그 메서드를 호출하는 데 사용된 객체(topval 메시지를 전달받은 객체)를 리턴한다.
그 메서드를 호출하는 데 사용된 객체(topval 메시지를 전달받은 객체)의 표현
->this포인터 : 멤버 함수를 호출하는데 사용된 객체를 지시
stock1.topval(stock2); 함수 호출은 this 포인터를 stock1 객체의 주소로 설정하고 topval 메서드에서 그 포인터를 사용
stock2.topval(stock1); 함수 호출은 this 포인터를 stock2 객체의 주소로 설정
-> 모든 클래스 메서드는 그 메서드를 호출하는 객체의 주소로 설정되는 하나의 this 포인터를 갖는다.
-> this는 그 객체의 주소이고 리턴해야하는 건 주소가 아닌 객체 자체이므로
const Stock& Stock::topval(const Stock & s) const
{
if (s.total_val > total_val)
return s; //매개변수로 전달받은 객체
else
return *this; //메서드를 호출한 객체
}
-> 리턴형이 참조면 리턴되는 객체가 복사본이 아닌 호출한 객체 그 자체라는 것을 의미한다.
//stock20.h
#ifndef STOCK20_H_
#define STOCK20_H_
#include <string>
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot() { total_val = shares * share_val; }
public:
//두 개의 생성자
Stock(); //디폴트 생성자
Stock(const std::string& co, long n = 0, double pr = 0.0);
~Stock(); //파괴자
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show() const;
const Stock& topval(const Stock& s)const;
};
#endif STOCK10_H_
//stock20.cpp
#include <iostream>
#include "stock20.h"
//생성자들
Stock::Stock() //디폴트 생성자
{
std::cout << "디폴트 생성자가 호출되었습니다. " << std::endl;
company = "no name";
shares = 0;
share_val = 0.0;
total_val = 0.0;
}
Stock::Stock(const std::string& co, long n, double pr)
{
std::cout << co << "를 사용하는 생성자가 호출되었습니다." << std::endl;
company = co;
if (n < 0)
{
std::cerr << "주식 수는 음수가 될 수 없으므로, "
<< company << " shares를 0으로 설정합니다" << std::endl;
shares = 0;
}
else
shares = n;
share_val = pr;
set_tot();
}
//클래스 파괴자
Stock::~Stock() //메시지를 출력하는 클래스 파괴자
{
std::cout << "안녕," << company << "!\n";
}
//다른 메서드들
void Stock::buy(long num, double price) //기존 보유 주식의 증가와 감소 관리
{
if (num < 0)
{
std::cout << "매입 주식 수는 음수가 될 수 없으므로, "
<< "거래가 취소되었습니다.\n";
}
else
{
shares += num;
share_val = price;
set_tot();
}
}
void Stock::sell(long num, double price) //기존 보유 주식의 감소 관리
{
using std::cout;
if (num < 0)
{
cout << "모두 주식 수는 음수가 될 수 없으므로, "
<< "거래가 취소되었습니다. \n";
}
else if (num > shares)
{
cout << "보유 주식보다 많은 주식을 매도할 수 없으므로, "
<< "거래가 취소되었습니다. \n";
}
else
{
shares -= num;
share_val = price;
set_tot();
}
}
void Stock::update(double price)
{
share_val = price;
set_tot();
}
//void Stock::show()
//{
// std::cout << "회사명: " << company
// << " 주식 수: " << shares << '\n'
// << " 주가: $" << share_val
// << " 주식 총 가치: $" << total_val << '\n';
//}
void Stock::show() const
{
using std::cout;
using std::ios_base;//fmtflags가 ios_base 클래스, std 이름공간에서 정의
//set format #.##
ios_base::fmtflags orig = //orig가 긴 타입 이름이 된다.
cout.setf(ios_base::fixed, ios_base::floatfield);
std::streamsize prec = cout.precision(2);
cout << "회사명: " << company
<< " 주식 수: " << shares << '\n';
cout << " 주가: $" << share_val;
//set format to #.##
cout.precision(2);
cout << " 주식 총 가치: $" << total_val << '\n';
//restore original format
cout.setf(orig, ios_base::floatfield);
cout.precision(prec);
}
const Stock& Stock::topval(const Stock& s) const
{
if (s.total_val > total_val)
return s; //매개변수로 전달받은 객체
else
return *this; //메서드를 호출한 객체
}
'Programming > C++ 2' 카테고리의 다른 글
[C++] 10장-7. 추상화 데이터형 (0) | 2021.04.12 |
---|---|
[C++] 10장-5. 객체 배열 (0) | 2021.04.11 |
[C++] 10장-3. 클래스 생성자와 파괴자 (0) | 2021.04.11 |
[C++] 10장-2. 추상화와 클래스 (0) | 2021.04.11 |
[C++ 요약] 3장. 데이터 처리 (0) | 2021.04.09 |