본문 바로가기

Programming/C++ 2

[C++] 10장-4. this 포인터

반응형

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; //메서드를 호출한 객체
}
반응형