정보 은닉


프로그래머가 실수를 했을때 , 실수가 쉽게 발견되게해야한다. 이를위해 제한된 방법으로의 접근만을 허용하여 잘못된 값이 저장되지않도록 도와야하고 , 실수를했을때 실수가 쉽게 발견될수있게해야한다. 따라서 멤버변수를 private로 선언하고 변수에 접근하는 함수를 별도로 정의해서 안전한형태로 멤버변수의 접근을 유도하는것이 바로 정보은닉이며 , 이는 좋은 클래스의 기본조건이다.


엑세스함수 (access funtion)


엑세스함수는 클래스외부에서 멤버변수 접근을 목적으로 정의되는 함수들이다. 클래스의 정의과정에서 당장은 필요없지만 필요할수있다고 판단되는 함수들을 멤버에 포함시키는 경우가 많은데 , 대표적인것이 엑세스함수이다.


int GetX() const; // const함수 , 멤버값을 불러오는함수

bool SetX(int xpos); // 멤버값을 설정하는함수


const 함수


int GetX() const;

void ShowRecInfo() const;


이때 const는 이 함수내에서는 멤버변수에 저장된값을 변경하지않겠다는 선언이다. 또한 const 함수 내에서는 const 함수가 아닌 함수들은 호출이 제한된다. 또한 const 참조자를 대상으로 값의 변경능력을 가진 함수의 호출도 허용하지않는다. (값의 변경여부와 관계없이)

따라서 const 선언을 사용하면 많은곳에 const선언을 추가해야하는 불편이있지만 , 그만큼 작성한 코드의 안정성은 높아진다.


ex)


class EasyClass

{

private : 

int num;

public :

int GetNum()

{    

return num;

}

void ShowNum() const  // const 함수

{

std::cout<<GetNum()<<std::endl; // const선언되지않은 GetNum() 함수호출 ( 에러 )

}

void InitNum( const EasyClass &easy) // const 참조자

{

num = easy.GetNum();  // const선언되지않은 GetNum() 함수 호출 ( 에러 )

};


캡슐화


하나의 목적을 달성하기위해 둘이상의 기능이 따로 작동해야한다면 캡슐화가 되지않은상태이고 , 둘이상의 기능이 모여서 작동한다면 캡슐화된 상태이다.

캡슐화시 , 하나의 클래스안에 모든것을 구성하는것이아니라 다른 클래스를 활용해도된다. 캡슐화를하면 복잡한 순서로 작동해야하는 기능도 비교적 간단하게 만들수 있다. 하지만 캡슐화의 범위를 정하는것이 쉬운일이 아니기때문에 , 캡슐화는 어려운개념이다.


생성자(Constructor)


생성자를 이용하면 객체 생성과 동시에 멤버를 초기화 할수있다.

생성자의 이름은 클래스의 이름과 동일하며 , 반환형이없고 , 객체생성시 딱 한번 호출된다.

생성자도 함수의 일종이니 오버로딩이 가능하고 , 디폴트값 설정이 가능하다.


class SimpleClass

{

private :

int num1;

int num2;

public :

SimpleClass()

{

num1=0;

num2=0;

}

SimpleClass(int n) // 생성자 , 반환형식없음

{

num1 = n;

num2 = 0;

}

SimpleClass(int n1 , n2)

{

num1 = n1;

num2 = n2;

}

};


SimpleClass sc(20); // 생성자를이용한 객체생성 ( 정적 )

SimpleClass * sc = new SimpleClass(20); // 생성자를 이용한 객체생성 ( 동적 )

SimpleClass sc;

SimpleClass * sc = new SimpleClass;

SimpleClass * sc = new SimpleClass();


하지만 주의할것이있는데, SimpleClass sc(); 와같은 방법으로는 객체생성을 할 수 없다.


SimpleClass sc1() // 반환형이 SimpleClass 인 일반함수

{

SimpleClass sc(20,30);

return sc;

}

이와같은 일반함수와 생성자의 호출을 컴파일러가 구분할수 없기때문에 , 매개변수없이 생성할때는 SimpleClass sc(); 와 같은 형태로 선언할 수 없다.


멤버 이니셜라이저 ( Member Initializer ) 를 이용한 멤버초기화


객체 생성 과정에서 클래스의 멤버를 생성자를 통해서 초기화하고싶을때 사용한다.


class Rectangle

{

private:

Point upleft;

Point lowRight;

public:

Rectangle(const int &x1,const int &y1,const int &x2,const int &y2) : upleft(x1,y1),lowright(x2,y2)

{

//empty , 멤버 이니셜라이저를 사용하다보면 생성자의 몸체부분이 비는일이 종종 발생

}

};


이때 : upleft(x1,y1),lowright(x2,y2) 이 내용이 멤버 이니셜라이저이다.

객체 upleft 의 생성과정에서 x1과 y1을 인자로 전달받는 생성자를 호출, 객체 lowright의 생성과정에서 x2와 y2를 인자로 전달받는 생성자를 호출


멤버이니셜라이저를 이용한 변수 및 const 상수(변수) 초기화


멤버 이니셜라이저는 객체가아닌 멤버의 초기화에도 사용가능하다.


class SoSimple

{

private:

int num1;

int num2;

public:

SoSimple(int n1,int n2) : num1(n1)

{

num2=2;

}

};


이때 num1(n1)은 num1을 n1값으로 초기화하라는뜻이된다. 멤버이니셜라이저를 이용하면 초기화의 대상을 명확히 인식할수 있으며 , 성능에 약간의 이점이있기때문에 멤버이니셜라이저를 쓰는편이 좋다. 

num1(n1)은 int num1=n1; 와 같고 , num2의 초기화는 int num2; num2=n2; 와 같기때문에 성능상의 차이가 발생한다.

이니셜라이저를 사용하면 선언과 동시에 초기화가 이뤄지는 형태로 바이너리 코드가 생성된다. const 멤버변수는 선언과 동시에 초기화해야하는데 , 멤버이니셜라이저를 사용하면 const 변수도 초기화가 가능하다는걸 알 수 있다. 또한 참조자변수도 선언과 동시에 초기화해야하는데 , 멤버이니셜라이저를 사용하여 초기화 가능하다.


디폴트 생성자 ( Default Constructor )


객체가 되기 위해서는 반드시 하나의 생성자가 호출되어야한다. 이러한 기준에 예외를 두지않기위해 생성자가 정의되지않은 클래스에는 C++컴파일러에의해 디폴트생성자가 자동으로삽입된다. 디폴트생성자는 인자를 받지않으며 , 내부적으로 아무일도 하지않는 생성자이다.


private 생성자


객체의 생성을 외부에서 진행할때는 public으로 생성자를 선언하지만, 클래스 내부에서 객체를 생성한다면 private로 생성자를 선언해도된다.

객체의 생성방법을 제한하고자하는 경우 유용하게 사용된다.


소멸자의 이해와 활용


소멸자는 클래스의 이름앞에 ~ 가붙은형태의 이름을 갖는다. 반환형이 선언되어있지않으며, 실제로 반환하지않는다. 매개변수는 void 형으로 선언되어야하기 때문에 오버로딩도 , 디폴트값 설정도 불가능하다.


~ 클래스_이름() { ... }


프로그래머가 소멸자를 정의하지않으면 디폴트생성자와 마찬가지로 디폴트 소멸자가 자동으로 삽입된다.


클래스와 배열 그리고 this 포인터


객체 배열


SoSimple arr[10]; // 객체배열의 정적할당

SoSimple * ptrArr = new SoSimple[10]; // 객체배열의 동적할당


배열의 선언과정에서는 호출할 생성자를 별도로 명시하지못하기때문에 ( 생성자에 인자를 전달하지 못한다 ) , SoSimple() { ... } 와 같은형태의 생성자가 반드시 정의되어있어야 한다.


객체 포인터배열


객체 포인터배열은 객체의 주소값 저장이 가능한 포인터 변수로 이루어진 배열이다.

SoSimple *parr[3] ; // parr에는 객체의 주소값 저장가능

parr[i] = new SoSimple(); // parr[i]에  힙영역에 생성된 SoSimple클래스의 주소값 저장


this 포인터


멤버함수 내에서는 this라는 이름의 포인터를 사용할수 있는데 , 이는 객체 자신을 가르키는 용도로 사용되는 포인터이다.

this 포인터를 활용하면 멤버변수와 매개변수가 같은이름일때 둘다 접근가능하다.


private:

int num;

public:

void ThisFunc(int num)

{

this ->num = 207; //멤버변수의 num

num=105; // 매개변수의 num

}


Self - Reference의 반환


Self - Reference란 객체 자신을 참조할 수 있는 참조자를 의미한다 . this 포인터를 이용해서 객체가 자신의 참조에 사용할 수 잇는 참조자의 반환문을 구성할 수 있다.


using namespace std;


class SelfRef

{

private:

int num;

public:

SelfRef(int n) : num(n)

{

cout<<"객체생성"<<endl;

}

SelfRef& Adder( int n)

{

num +=n;

return *this;

}

SelfRef& ShowTwoNumber()

{

cout << num<<endl;

return * this;

}

};


int main(void)

{

SelfRef obj(3);

SelfRef &ref = obj.Adder; // ref 참조자에 obj 객체 입력 ( obj 객체에 ref 라는 별명생김)


obj.ShowTwoNumber();

ref.ShowTowNumber();


ref.Adder(1).ShowTwoNumber().Adder(2).ShowTwoNumber(); // Adder()와 ShowTwoNumber() 두함수가 모두 자기자신객체의 참조값을 반환하기때문에 구성이 가능한 문장이다.

return 0;

}



+ Recent posts