[C++] Chapter 06 - friend와 static 그리고 const

Lee Jeong Min·2021년 1월 7일
0

Cpp

목록 보기
6/16
post-thumbnail

06-1 const와 관련해서 아직 못다한 이야기

const 객체와 const 객체의 특성들

const int num1 = 10;
const SoSimple sim(20);

다음과 같이 객체도 상수화 할수 있음 이러한 const선언이 붙게 되면 이 객체를 대상으로 const 멤버 함숨나 호출이 가능해진다.

const와 함수 오버로딩

#include <iostream>
using namespace std;

class SoSimple
{
private:
	int num;
public:
	SoSimple(int n) : num(n)
	{

	}
	SoSimple& AddNum(int n)
	{
		num += n;
		return *this;
	}
	void SimpleFunc()
	{
		cout << "SimpleFunc: " << num << endl;
	}
	void SimpleFunc() const
	{
		cout << "const SimpleFunc: " << num << endl;
	}
};

void YourFunc(const SoSimple& obj)
{
	obj.SimpleFunc();
}

int main(void)
{
	SoSimple obj1(2);
	const SoSimple obj2(7);

	obj1.SimpleFunc();
	obj2.SimpleFunc();

	YourFunc(obj1);
	YourFunc(obj2);
	return 0;
}

이를 확인하면 main함수에서 YourFunc실행시 인자로 const 객체를 받기 때문에 결과에서 void SimpleFunc() const가 실행이 됨.


06-2 클래스와 함수에 대한 friend 선언

friend를 선언하게 되면 private의 멤버의 접근을 허용하게 해줌

#include <iostream>
#include <cstring>
using namespace std;

class Girl;

class Boy
{
private:
	int height;
	friend class Girl; // girl 클래스에 대한 friend 선언
    //이를 통해 girl클래스 내에서 boy크래스의 모든 private멤버에 직접접근이 가능함
public:
	Boy(int len) : height(len)
	{

	}
	void ShowYourFriendInfo(Girl& frn);
};

class Girl
{
private:
	char phNum[20];
public:
	Girl(const char* num)
	{
		strcpy(phNum, num);
	}
	void ShowYourFriendInfo(Boy& frn);
	friend class Boy;
};

void Boy::ShowYourFriendInfo(Girl& frn)
{
	cout << "Her phone number: " << frn.phNum << endl;
}

void Girl::ShowYourFriendInfo(Boy& frn)
{
	cout << "His height: " << frn.height << endl;
}

int main(void)
{
	Boy boy(170);
	Girl girl("010-1234-5678");
	boy.ShowYourFriendInfo(girl);
	girl.ShowYourFriendInfo(boy);
	return 0;
}

5번 째 행의 class Girl; 없이도 실행이 가능한데 그 이유가 boy클래스의 private 멤버 변수에 friend class Girl이 선언이 되어있는데 이는 Girl이 클래스의 이름이라는 것과 Girl class를 friend로 선언한다는 2가지의 의미를 갖고 있기 때문이다.

함수의 friend 선언

#include <iostream>
using namespace std;

class Point;

class PointOP
{
private:
	int opcnt;
public:
	PointOP() :opcnt(0)
	{

	}
	Point PointAdd(const Point&, const Point&);
	Point Pointsub(const Point&, const Point&);
	~PointOP()
	{
		cout << "Operation times: " << opcnt << endl;
	}
};

class Point
{
private:
	int x;
	int y;
public:
	Point(const int &xpos, const int &ypos) : x(xpos), y(ypos)
	{}
	friend Point PointOP::PointAdd(const Point&, const Point&);
	friend Point PointOP::Pointsub(const Point&, const Point&);
	friend void ShowPointPos(const Point&);
};

Point PointOP::PointAdd(const Point& pnt1, const Point& pnt2)
{
	opcnt++;
	return Point(pnt1.x + pnt2.x, pnt1.y + pnt2.y);
}

Point PointOP::Pointsub(const Point& pnt1, const Point& pnt2)
{
	opcnt++;
	return Point(pnt1.x - pnt2.x, pnt1.y - pnt2.y);
}

int main(void)
{
	Point pos1(1, 2);
	Point pos2(2, 4);
	PointOP op;
	
	ShowPointPos(op.PointAdd(pos1, pos2));
	ShowPointPos(op.Pointsub(pos1, pos2));

	return 0;
}

void ShowPointPos(const Point& pos)
{
	cout << "x: " << pos.x << ", ";
	cout << "y: " << pos.y << endl;
}

이 코드에선 PointADD와 PointSub함수가 friend로 POINT내에서 선언이 되었기 때문에 private멤버 변수에 접근이 가능한 모습을 볼 수 있다. ShowPointPos도 마찬가지
함수도 마찬가지로 friend void ShowPointPos(const Point&)에서 friend 선언이외에 함수 원형 선언이 포함되어 있기 때문에 따로 함수원형을 선언할 필요가 없다.


06-3 C++에서의 static

C언어에서 이야기한 static

  • 전역 변수에 선언된 static의 의미: 선언된 파일 내에서만 참조를 허용하겠다는 의미
  • 함수 내에 선언된 static의 의미: 한번만 초기화되고, 지역변수와 달리 함수를 빠져나가도 소멸되지 않는다.

전역변수가 필요한 상황

일반적으로 static을 사용하지 않고 전역변수가 필요한 상황이 있을 때 전역변수를 사용하게 되면 어디서든 접근이 가능하므로 코드 자체가 위험해 질 수 있으므로 static을 활용하여 사용함!
static 멤버변수를 보통 클래스 변수라고 부르는데 일반적인 멤버 변수와 달리 클래스당 하나씩만 생성되기 때문이다.

#include <iostream>
using namespace std;

class SoSimple
{
private:
	static int simObjCnt;
public:
	SoSimple()
	{
		simObjCnt++;
		cout << simObjCnt << "번째 SoSimple 객체" << endl;
	}
};
int SoSimple::simObjCnt = 0;

class SoComplex
{
private:
	static int cmxObjCnt;
public:
	SoComplex()
	{
		cmxObjCnt++;
		cout << cmxObjCnt << "번째 SoComplex 객체" << endl;
	}
	SoComplex(SoComplex& copy)
	{
		cmxObjCnt++;
		cout << cmxObjCnt << "번째 SoComplex 객체" << endl;
	}
};
int SoComplex::cmxObjCnt = 0;

int main(void)
{
	SoSimple sim1;
	SoSimple sim2;

	SoComplex cmx1;
	SoComplex cmx2 = cmx1;
	SoComplex();
	return 0;
}

static을 사용함으로써 각 class마다 접근범위를 설정할 수 있다.
또한 static 변수를 생성자내에서 초기하지 않는 이유는 다른 객체가 생성될 때마다 동시에 생성되는 변수가 아닌 이미 메모리 공간에 할당이 이뤄진 변수이기 때문이다.
static을 public으로 선언을 하게되면 객체의 이름을 통해 어디서든 접근이 가능하지만 멤버 변수에 접근하는 것과 같은 오해를 불러 일으키므로 비추천.

static 멤버함수

  • 선언된 클래스의 모든 객체가 공유한다.
  • public으로 선언되면 클래스의 이름을 이용해서 호출이 가능하다.
  • 객체의 멤버로 존재하는 것이 아니다.

위의 특성 중 특히 3번째 특성 때문에 static 멤버함수 내에서는 static 멤버변수와 static 멤버함수만 호출이 가능하다

const static 멤버

const 멤버변수의 초기화는 이니셜라이저를 통해서만 가능하였지만 const static으로 선언되는 멤버 변수는 선언과 동시에 초기화가 가능하다!

class CountryArea
{
public:
    const static int RUSSIA = 1707540;
    const static int CHINA = 957290;
};

키워드 mutable

mutable은 const 함수내에서 값의 변경을 예외적으로 허용하게 해줌.

#include <iostream>
using namespace std;

class SoSimple
{
private:
	int num1;
	mutable int num2;
public:
	SoSimple(int n1, int n2) : num1(n1), num2(n2)
	{}
	void ShowSimpleData() const
	{
		cout << num1 << ", " << num2 << endl;
	}
	void CopyToNum2() const
	{
		num2 = num1;
	}
};

int main(void)
{
	SoSimple sm(1, 2);
	sm.ShowSimpleData();
	sm.CopyToNum2();
	sm.ShowSimpleData();
	return 0;
}
profile
It is possible for ordinary people to choose to be extraordinary.

0개의 댓글