'분류 전체보기'에 해당되는 글 590건

  1. 2012.05.23 explicit
  2. 2012.05.22 복사 생성자(Copy Constructor)
  3. 2012.05.21 this 포인터
  4. 2012.05.21 객체 배열 & 객체 포인터 배열
  5. 2012.05.21 생성자 & 소멸자를 이용한 예제
  6. 2012.05.21 생성자를 이용한 예제.
  7. 2012.05.20 소멸자(Destructor)
  8. 2012.05.20 private 생성자

explicit

Programming/C++ 2012. 5. 23. 00:51 |

변환에 의한 초기화를 막는 키워드 "explicit"



Simple sim2 = sim1;    =>    Simple sim2(sim1);

묵시적 변환이 일어나서 복사 생성자가 호출된다.


이는 결국, 복사 생성자가 묵시적으로 호출된 것으로 볼 수 있다. 따라서 위와 같은 유형의 변환이 마음에 들지 않느다면, 복사 생성자의 묵시적 호출을 허용하지 않으면 된다. 그리고 이러한 목적으로 사용되는 키워드가 explicit 이다.




13행:

explicit Simple(const Simple &copy)

:num(copy.num)

{ }


더 이상 묵시적 변환이 발생하지 않아서 대입 연산자를 이용한 객체의 생성 및 초기화는 불가능하다.


※ 묵시적 변환이 좋은 것만은 아니다.

자료형이든, 문장이든 자동으로 변환되는 것이 늘 좋은 것만은 아니다. 묵시적 변환이 많이 발생하는 코드일수록 코드의 결과를 예측하기가 어려워지기 때문이다. 따라서 키워드 explicit 는 코드의 명확함을 더하기 위해서 자주 사용되는 키워드 중 하나이다.


그리고 이러한 문장의 묵시적 변환은 복사 생성자에서만 일어나는 게 아니다. 전달인자가 하나인 생성자가 있다면, 이 역시 묵시적 변환이 발생한다. 

ex)

class ABC

{

int num;


public:

ABC(int n) : num(n) { }

...

};


다음의 문장을 통해서 객체생성이 가능하다.


ABC obj = 3;        // ABC obj(3); 으로 변환.


이 경우에도 마찬가지로 키워드 explicit 가 생성자에 선언되면, 묵시적인 변환을 허용하지 않기 때문에 다음의 형태로 객체를 생성할 수밖에 없다.


ABC obj(3);

'Programming > C++' 카테고리의 다른 글

복사 생성자의 호출시점  (0) 2012.05.25
깊은 복사 & 얕은 복사  (0) 2012.05.24
복사 생성자(Copy Constructor)  (0) 2012.05.22
this 포인터  (0) 2012.05.21
객체 배열 & 객체 포인터 배열  (0) 2012.05.21
Posted by scii
:

복사 생성자


C++에서는 다음의 방식으로 선언 및 초기화가 가능하다.

int num(20);






Simple형 객체를 생성해라.

객체의 이름은 sim2로 정한다.

sim1을 인자로 받을 수 있는 생성자의 호출을 통해서 객체생성을 완료한다.


위의 객체생성문에서 호출하고자 하는 생성자는 다음과 같이 Simple 객체를 인자로 받을 수 있는 생성자이다.


Simple(Simple &copy)

{

}


그리고 다음의 문장도, 

Simple sim2 = sim1;


실은 다음의 형태로 묵시적 변환이 되어서(자동으로 변환이 되어서) 객체가 생성되는 것이다.

Simple sim2(sim1);



----------------------------------------------------------------------------------------------------------------------------------------




32행의 문장이 묵시적으로(자동으로) 변환된다는 사실만 제외하면 특별할 게 없는 예제이다. 14행에 정의된 생성자도 이해할만한 수준의 생성자이다. 그런데 이러한 생성자를 가리켜 별도로 "복사 생성자(Copy Constructor)" 라 부른다.

이는 생성자의 정의형태가 독특해서 붙은 이름이 아니다. 다만 이 생성자가 호출되는 시점이 다른 일반 생성자와 차이가 있기 때문에 붙은 것이다.

즉, 복사 생성자를 정확히 이해하기 위해서는 복사 생성자의 호출시점을 확실히 이해해야 한다.


----------------------------------------------------------------------------------------------------------------------------------------


자동으로 삽입이 되는 디폴트 복사 생성자


: 복사 생성자를 정의하지 않으면, 멤버 대 멤버의 복사를 진행하는 디폴트 복사 생성자가 자동으로 삽입된다.


생성자가 존재하더라도, 복사 생성자가 정의되어 있지 않으면 디폴트 복사 생성자라는 것이 삽이되어 멤버 대 멤버의 복사를 진행한다.


class Simple

{

int num1;

int num2;


public:

Simple(int n1, int n2) : num1(n1), num2(n2)

{ }

};


class Simple

{

int num1;

int num2;


public:

Simple(int n1, int n2) : num1(n1), num2(n2)

{ }

Simple(const Simple &copy)  : num1(copy.num1), num2(copy.num2)

{ }

};


위의 두 클래스 정의는 완전히 동일한 것이다. 디폴트 복사 생성자가 자동으로 삽입되기 때문이다.


※ 많은 경우에 있어서 복사 생성자를 직접 정의하지 않아도 된다. 그러나 반드시 복사 생성자를 정의해야 하는 경우도 있다.

'Programming > C++' 카테고리의 다른 글

깊은 복사 & 얕은 복사  (0) 2012.05.24
explicit  (0) 2012.05.23
this 포인터  (0) 2012.05.21
객체 배열 & 객체 포인터 배열  (0) 2012.05.21
생성자 & 소멸자를 이용한 예제  (0) 2012.05.21
Posted by scii
:

this 포인터

Programming/C++ 2012. 5. 21. 23:35 |

this 포인


: 멤버함수(메소드) 내에서는 this라는 이름의 포인터를 사용할 수 있는데, 이는 객체 자신을 가리키는 용도로 사용되는 포인터이다.(this는 객체를 참조하는 포인터이다)




실행결과를 통해 this는 객체 자신의 주소 값을 의미한다는 사실을 알 수 있다.

이렇듯 this 포인터는 그 주소 값과 자료형이 정해져 있지 않은 포인터이다.



this 포인터의 활용


class ThisClass

{

private:

int num;                        //207이 저장됨.


public:

void ThisFunc(int num)

{

this->num = 207;

num = 105;            //매개변수의 값을 105로 변경함.

}

};


위의 클래스에서 ThisFunc 함수의 매개변수 이름은 num이다. 그런데 이 이름은 멤버변수의 이름과 동일하기 때문에 ThisFunc 함수 내에서의 num은 매개변수 num을 의미하게 된다(지역변수는 매개변수에 의해 가려진다).

따라서 변수의 이름만 참조하는 방법으로는 ThisFunc 함수 내에서 멤버변수 num에 접근이 불가능하다. 그러나 this 포인터를 활용하면 가능하다.


this->num = 207;


위 문장에서 this는 객체를 참조하는 포인터이다. 객체의 포인터를 가지고는 지역변수에 접근이 불가능하다. 따라서 이는 멤버변수 num을 의미하는 것이다. 이러한 특성을 활용하면, 매개변수의 이름을 멤버변수의 이름과 달리하기 위해서 고민할 필요가 없다.





------------------------------------------------------------------------------------------------------------------------------------------




15행: 함수 Adder에서는 선언된 반환형과 반환의 내용을 함께 살펴야 한다. 반환의 내용은 *this인데, 이는 이 문장을 실행하는 객체 자신의 포인터가 아닌, 객체 자신을 반환하겠다는 의미가 된다. 그런데 반환형이 참조형 SelfRef& 으로 선언되었다. 따라서 객체 자신을 참조할 수 있는 '참조의 정보(참조 값)' 가 반환된다.


30행: 객체 obj의 Adder 함수를 호출하였다. 그런데 이 함수는 객체 자신의 참조 값을 반환한다. 즉, 객체 obj의 참조 값을 반환한다. 따라서 참조자 ref는 객체 obj를 참조하게 된다.


35행: 먼저 객체 ref의 Adder 함수가 호출된다. 그런데 Adder 함수는 참조 값을 반환하므로, 반환된 참조 값을 이용해서 다시 ShowTwoNumber 함수를 호출하게 된다. 그리고 마찬가지로 반환되는 참조 값을 이용해서 다시 Adder 함수를 호출하고, 또 이어서 객체의 참조 값을 반환하기 때문에 구성이 가능한 문장이다.


※ 객체가 반환하는 참조 값을 대상으로 다양한 방법으로 멤버함수를 호출한 것.

'Programming > C++' 카테고리의 다른 글

explicit  (0) 2012.05.23
복사 생성자(Copy Constructor)  (0) 2012.05.22
객체 배열 & 객체 포인터 배열  (0) 2012.05.21
생성자 & 소멸자를 이용한 예제  (0) 2012.05.21
생성자를 이용한 예제.  (0) 2012.05.21
Posted by scii
:

객체 배열


: 객체 배열 및 객체 포인터 배열은 C언어의 구조체 배열과 구조체 포이터 배열과 유사하다.


객체 기반의 배열은 다음의 형태로 선언한다(Simple이 클래스 이름).

Simple arr[10];


이를 동적으로 할당하는 경우에는 다음의 형태로 선언한다.

Simple * ptrArr = new Simple[10];


이러한 형태로 배열을 선언하면, 열 개의 Simple 객체가 모여서 배열을 구성하는 형태가 된다. 이렇듯 구조체 배열의 선언과 차이가 없다.

하지만 배열을 선언하는 경우에도 생성자는 호출이 된다. 단, 배열의 선언과정에서는 호출할 생성자를 별도로 명시하지 못한다(생성자에 인자를 전달하지 못한다). 즉, 위의 형태로 배열이 생성되려면 다음 형태의 생성자가 반드시 정의되어 있어야 한다.

Simple(void) {...}


그리고 배열 선언 이후에 각각의 요소를 원하는 값으로 초기화시키길 원한다면, 일일이 초기화의 과정을 별도로 거쳐야 한다.



객체 배열의 예제

#include <iostream>

#include <cstring>

using namespace std;


class Person

{

private:

char * name;

int age;


public:

Person(char* myname, int myage)             //생성자

:age(myage)

{

int len = strlen(myname);

name = new char[len];

strcpy(name, myname);

}

Person() //생성자. 배열 생성시 필요한 생성자를 추가하였다.

{

name = NULL;

age = 0;

cout<<"called Person()"<<endl;

}

void SetPersonInfo(char * myname, int myage)

{

name = myname;

age = myage;

}

void ShowPersonInfo() const

{

cout<<"이름: "<<name<<", "<<"나이: "<<age<<endl;

}

~Person() //소멸자

{

delete []name;

cout<<"called Destructor!"<<endl;

}

};


int main(void)

{

Person pArr[3];             //class Person 3개를 가지고있는 배열.

char nameStr[100];

char * strPtr;

int age;

int len;


for(int i=0; i<3; i++)

{

cout<<"이름: ";

cin>>nameStr;

cout<<"나이: ";

cin>>age;

len = strlen(nameStr)+1;

strPtr = new char[len];

strcpy(strPtr, nameStr);

pArr[i].SetPersonInfo(strPtr, age);

}


for(int i=0; i<3; i++)

pArr[i].ShowPersonInfo();


return 0;

}


실행결과




객체 배열 생성시 void형 생성자가 호출됨을 확인할 수 있다. 그리고 배열 소멸시에도 그 배열을 구성하는 객체의 소멸자가 호출됨을 확인할 수 있다.


-----------------------------------------------------------------------------------


객체 포인터 배열


: 객체 배열이 객체로 이뤄진 배열이라면, 객체 포인터 배열은 객체의 주소 값 저장이 가능한 포인터 변수로 이뤄진 배열이다.


#include <iostream>

#include <cstring>

using namespace std;


class Person

{

private:

char * name;

int age;


public:

Person(char* myname, int myage)             //생성자

:age(myage)

{

int len = strlen(myname)+1;

name = new char[len];

strcpy(name, myname);

}

void ShowPersonInfo() const

{

cout<<"이름: "<<name<<", "<<"나이: "<<age<<endl;

}

~Person() //소멸자

{

delete []name;

cout<<"called Destructor!"<<endl;

}

};


int main(void)

{

Person* pArr[3];                 //class Person 가리킬 수 있는 객체 포인트 배열.

char nameStr[100];

int age;


for(int i=0; i<3; i++)

{

cout<<"이름: ";

cin>>nameStr;

cout<<"나이: ";

cin>>age;

pArr[i] = new Person(nameStr, age);    //객체를 생성해서, 이 객체의 주소 값을 배열에 저장하고 있다.

}


for(int i=0; i<3; i++)

{

pArr[i]->ShowPersonInfo();

delete pArr[i]; //new연산을 진행하였으니 delete연산 진행.

}


return 0;

}


실행결과




※ 객체를 저장할 때에는 위의 예제에서 보인 두 가지 방법 중 하나를 택해야 한다. 즉, 저장의 대상을 객체로 하느냐, 객체의 주소 값으로 하느냐를 결정해야 한다.


'Programming > C++' 카테고리의 다른 글

복사 생성자(Copy Constructor)  (0) 2012.05.22
this 포인터  (0) 2012.05.21
생성자 & 소멸자를 이용한 예제  (0) 2012.05.21
생성자를 이용한 예제.  (0) 2012.05.21
소멸자(Destructor)  (0) 2012.05.20
Posted by scii
:

#include <iostream>

#include <cstring>

using namespace std;


namespace COMP_POS

{

enum {CLERK, SENIOR, ASSIST, MANAGER};


void Select(int pos)

{

switch(pos)

{

case CLERK:

cout<<"사원"<<endl; break;

case SENIOR:

cout<<"주임"<<endl; break;

case ASSIST:

cout<<"대리"<<endl; break;

case MANAGER:

cout<<"과장"<<endl; break;

}

}

}


class NameCard

{

private:

char * name;

char * companyName;

char * tel;

int position;


public:

NameCard(char* na, char* comp, char* tele, int pos)        //생성자

:position(pos)                                

{

int len1 = strlen(na)+1;

int len2 = strlen(comp)+1;

int len3 = strlen(tele)+1;

name = new char[len1];

strcpy(name, na);

companyName = new char[len2];

strcpy(companyName, comp);


tel = new char[len3];

strcpy(tel, tele);

}

void ShowNameCardInfo(void) const

{

cout<<"이름 :"<<name<<endl;

cout<<"회사 :"<<companyName<<endl;

cout<<"전화번호 :"<<tel<<endl;

cout<<"직급 :"; COMP_POS::Select(position);

cout<<endl;

}

~NameCard()                                                            //소멸자

{

delete []name;

delete []companyName;

delete []tel;

}

};


int main(void)

{

NameCard manClerk("Lee", "abc", "010-875-5543", COMP_POS::CLERK);

NameCard manSenior("Jane", "def", "010-232-3439", COMP_POS::SENIOR);

NameCard manAssist("Jeon", "ghi", "010-844-1245", COMP_POS::ASSIST);


manClerk.ShowNameCardInfo();

manSenior.ShowNameCardInfo();

manAssist.ShowNameCardInfo();


return 0;

}


실행결과



'Programming > C++' 카테고리의 다른 글

this 포인터  (0) 2012.05.21
객체 배열 & 객체 포인터 배열  (0) 2012.05.21
생성자를 이용한 예제.  (0) 2012.05.21
소멸자(Destructor)  (0) 2012.05.20
private 생성자  (0) 2012.05.20
Posted by scii
:

Point 클래스는 점의 좌표를 알려주는 클래스이고, Circle 클래스는 원의 반지름과 중심점의 좌표를 알려주는 클래스이다. 그리고 마지막으로 Ring클래스는 Point, Circle 클래스를 묶는(캡슐화) 클래스이다. Ring클래스는 좌표정보와 반지름을 입력받아 Point, Circle에 전달한다. 


#include <iostream>

using namespace std;


class Point

{

private:

int xpos, ypos;


public:

Point(int x, int y) : xpos(x), ypos(y)         //Constructor

{}

void ShowPointInfo(void) const

{

cout<<"["<<xpos<<", "<<ypos<<"]"<<endl;

}

};


class Circle

{

private:

Point coord;

const int rad;


public:

Circle(const int x, const int y, const int r)

:coord(x, y), rad(r) //Constructor

{}

void ShowCircleInfo(void) const

{

cout<<"radius: "<<rad<<endl;

coord.ShowPointInfo();

}

};


class Ring

{

private:

Circle c1;

Circle c2;


public:

Ring(int x1, int y1, int r1, int x2, int y2, int r2)

:c1(x1, y1, r1), c2(x2, y2, r2)         //Constructor

{}

void ShowRingInfo(void) const

{

cout<<"Inner Circle Info..."<<endl;

c1.ShowCircleInfo();

cout<<"Outter Circle Info..."<<endl;

c2.ShowCircleInfo();

}

};


int main(void)

{

Ring ring(1, 1, 4, 2, 2, 9);

ring.ShowRingInfo();


return 0;

}


실행결과



'Programming > C++' 카테고리의 다른 글

객체 배열 & 객체 포인터 배열  (0) 2012.05.21
생성자 & 소멸자를 이용한 예제  (0) 2012.05.21
소멸자(Destructor)  (0) 2012.05.20
private 생성자  (0) 2012.05.20
디폴트 생성자(Default Constructor)  (0) 2012.05.20
Posted by scii
:

소멸자(Destructor)

Programming/C++ 2012. 5. 20. 14:44 |

객체생성시 반드시 호출되는 것이 생성자라면, 객체소멸시 반드시 호출되는 것은 소멸자이다.


* 클래스의 이름 앞에 '~'가 붙은 형태의 이름을 갖는다.

* 반환형이 선언되어 있지 않으며, 실제로 반환하지 않는다.

* 매개변수는 void형으로 선언되어야 하기 때문에 오버로딩도, 디폴트 값 설정도 불가능하다.


ex) ~AAA(void) {...}


소멸자는 객체소멸 과정에서 자동으로 호출이 된다. 그리고 프로그래머가 직접 소멸자를 정의하지 않으면, 디폴트 생성자와 마찬가지로 아무런 일도 하지 않는 디폴트 소멸자가 자동으로 삽입된다.


class AAA

{

// empty class

};


class AAA

{

public:

AAA() {}

~AAA() {}

};


위의 2개의 클래스는 100% 동일한 클래스이다.



소멸자는 대표적으로 말하자면 클래스내에서 힙영역에 생성한 메모리공간을 없애는데 사용이 된다.





'Programming > C++' 카테고리의 다른 글

생성자 & 소멸자를 이용한 예제  (0) 2012.05.21
생성자를 이용한 예제.  (0) 2012.05.21
private 생성자  (0) 2012.05.20
디폴트 생성자(Default Constructor)  (0) 2012.05.20
이니셜라이저(Initializer)  (0) 2012.05.19
Posted by scii
:

private 생성자

Programming/C++ 2012. 5. 20. 03:40 |

private 생성자


: 클래스 내부에서만 객체의 생성을 허용하려는 목적으로 생성자를 private으로  선언하기도 한다.




여기서는 힙 영역에 생성된 객체를 참조의 형태로 반환하고 있다.


"힙에 할당된 메모리 공간은 변수로 간주하여, 참조자를 통한 참조가 가능하다."


private 생성자는 때로 유용하게 사용된다. 특히, 객체의 생성방법을 제한하고자 하는 경우에는 매우 유용하게 사용이 된다.


'Programming > C++' 카테고리의 다른 글

생성자를 이용한 예제.  (0) 2012.05.21
소멸자(Destructor)  (0) 2012.05.20
디폴트 생성자(Default Constructor)  (0) 2012.05.20
이니셜라이저(Initializer)  (0) 2012.05.19
생성자(Constructor)  (0) 2012.05.12
Posted by scii
: