[C++] 7.friend와 static 그리고 const


const 객체와 const 객체의 특성



변수를 const를 사용하여 상수화 하듯이,

다음과 같이 객체도 상수화할 수 있습니다.

const example ex1(20);



이렇게 객체에 const 선언이 붙게 되면, 이 객체를 대상으로는 const 멤버함수만 호출이 가능합니다.

왜냐하면, const 선언은 이 객체의 데이터변경을 허용하지 않기 때문입니다.


class example
{
private:
	int num;
public:
	example(int n) : num(n){}
	void show() const {...}
	void Add() {...}
};

int main(void)
{
	const example ex(3); //const 객체 선언
	
	ex.show(); //호출가능
	
	ex.Add(); //호출 불가
	
	return 0;
}



비록 멤버함수가 멤버변수를 변경하지 않더라도, const 객체는 그 멤버함수를 호출할 수 없습니다.

따라서, 멤버변수에 저장된 값을 수정하지 않는 함수는 가급적 const로 선언해야합니다.

또한, 함수 오버로딩에서 함수의 오버로딩이 성립하려면,

매개변수의 수나 자료형이 달라야한다고 하였는데요~

다음과 같이 const의 선언유무도 함수 오버로딩의 조건에 해당이 됩니다.


void function(){...}

void function() const {...}



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



어떤 클래스에서 private로 선언된 멤버변수와 멤버함수에는

다른 클래스나 외부에서 접근을 할 수 없었습니다.

하지만, friend 라는 키워드를 사용하면 private 멤버의 접근이 가능합니다.

말그대로 친구끼리는 모두 공유하는 것이죠~~


class A
{
private:
	int num; //다른 클래스에서 접근 X
	friend class B//B 클래스를 friend로 선언함

public:
	...
	...
}

class B
{
private:
	int num;
	
public:
	B(int n) : num(n){}
	void A_show(A &frn)
	{
		cout<<frn.num<<endl; //A의 private 변수에 접근가능
	}
};



만약 B의 private 변수에 A도 접근하고 싶으면 다음과 같이 friend 선언을 추가해야합니다.


class B
{
private:
	int  num;
	friend class A; //A 클래스에 대한 friend 선언
public:
	...
};



friend 선언은 클래스 내부 어디라도 선언해도 상관없습니다~

또한 friend 선언은 함수에도 사용 가능합니다.


class A
{
private:
	int num;
	friend void show(const A& frn); //전역 함수를 대상으로 friend 선언
public:
	...
};

void show(const A& frn)
{
	cout<<frn.num<<endl; //A의 private 변수에 접근가능
}

//또한 A 클래스에서 friend 선언 동시에 show의 함수원형을 정의하고 있으므로

//함수원형을 다시 정의할 필요는 없습니다.



friend 키워드는 전에 얘기한 정보은닉을 무너뜨리는 문법이기에 자주 사용하는 것은,

좋지 않습니다~

나중에 연산자 오버로딩에 사용되기에,

일단은, 문법적으로 이해하만 하시고 가급적 사용하지 마시길 바랍니다~



C++에서의 static



C언어에서 공부한 Static의 개념을 정리해보겠습니다.

전역변수에 선언된 static 의미

	선언된 파일 내에서만 참조를 허용하겠다는 의미

함수 내에 선언된 static 의미

	한번만 초기화되고, 지역변수와 달리 함수를 빠져나가도 소멸되지 않는다.



C언어에서의 static은 C++에서도 그대로 통용됩니다.

게다가 C++에서는 멤버변수와 멤버함수에 static 선언을 추가할 수 있습니다.


class example
{
private:
	static int cnum; //멤버변수의 static 선언
public:
	...
};



static 멤버 변수는 클래식 변수라고 하는데,

일반 멤버변수와 달리 클래스 당 하나씩만 생성이 됩니다.

그리고 그 클래스의 객체들은 이 static 멤버변수를 공유합니다~!

말이 멤버 변수지, 그 클래스만 사용하는 전역변수라고 생각하시면 됩니다.

객체 내에 생성되는 변수가 아니라 외부에 생성되는 변수이기 때문입니다.

따라서 클래스 변수 초기화도 내부(생성자)가 아닌 외부에서 이뤄져야 합니다~


int example::cnum=0; //클래스 외부에서 static 멤버변수의 초기화



static 변수에 접근하는 방법은 두가지가 있습니다.


int main(void)
{
	cout<<example::cnum<<endl; //첫번째 ::을 이용한 접근
	
	example ex1;
	cout<<ex1.cnum<<endl; //두번째 .을 이용한 접근
	
	return 0;
}



두번째 접근 방법은 클래스 변수에 접근하는 것인지 일반적인 멤버변수에 접근하는 것인지,

오해를 불러 일으킬 수 있으므로 클래스 변수는 첫번째 방법으로

접근하는 것이 좋습니다~~~

static 멤버 함수도 역시 그 특성이 static 멤버변수와 동일합니다.

선언된 클래스의 모든 객체가 공유하는 함수이고,

public으로 선언이 되면, 클래스의 이름을 이용해서 호출이 가능합니다.

하지만 static 멤버함수 내에서는 static 멤버변수와 static 멤버함수만 호출이 가능합니다.


class example
{
private:
	int num1;
	static int num2;
public:
	example(int n) :num1(n){}
	static void function(void) //static 멤버 함수
	{
		num1++; //컴파일 에러
		num2++;//가능
	}
};



const static 멤버



클래스 내에서 선언된 const 멤버변수의 초기화는 이니셜라이져를 통해서 해야만 합니다.

하지만 const static으로 선언되는 멤버변수는 다음과 같이 초기화가 가능합니다.

class example
{
public:
	const static int NUM=10; //컴파일 허용
	...
};



키워드 mutable



mutable은 const 함수 내에서의 값의 변경을 예외적으로 허용한다고 알고 있으면 됩니다.

class example
{
private:
	int num1;
	mutable int num2; //const 함수에 대해 예외를 둔다!
public:
	...
	void function(void) const //const 함수
	{
		num1++; //컴파일에러
		num2++; //허용
	}
};



키워드 mutable은 가급적 빈도수를 낮춰야 하는 키워드입니다.

const의 선언을 의미없게 만들 수 있기 때문입니다.

그렇기에 자세히 알 필요는 없습니다~