본문 바로가기
코스웨어/16년 스마트컨트롤러

2016-09-27_조재찬_스터디일지_CPP-객체 배열과 this포인터, Self-Ref.

by 알 수 없는 사용자 2016. 9. 27.
728x90
반응형

객체 배열

: 객체를 기반으로 객체 배열의 선언이 가능하다.


클래스 이름이 SoSimple일 때, 객체 기반의 배열을 다음과 같이 선언한다.


SoSimple arr[10];


동적 할당

SoSimple * ptrArr = new SoSimple[10];


이러한 형태의 배열 선언은, 열개의 SoSimple 객체가 모여서 배열을 구성하는 형태이다.

이 경우에도 생성자는 호출이 되나, 배열 선언과정에서는 호출할 생성자를 별도로 명시하지 못한다. (생성자에 인자를 전달하지 못함)


위와 같이 객체 기반 배열이 생성되려면 다음 형태의 생성자가 반드시 정의되야 하낟.

So Simple() { . . . .}


#include <cstring> // c의 string 함수 include

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

class Person
{
private:
	char * name;
	int age;

public:
	Person(char * myname, int myage)
	{
		int len = strlen(myname) + 1;
		name = new char[len];
		strcpy(name, myname);
		age = myage;
	}
	Person()	// 배열 생성시 필요한 생성자 정의
	{
		name = NULL;
		age = 0;
		cout << "called Person()" << endl;
	}

	void SetPersonInfo(char * myname, int myage)	// 초기화 함수
	{
		name = myname;
		age = myage;
	}
	void ShowPersonInfo() const
	{
		cout << "이름: " << name << ", ";
		cout << "나이: " << age << endl;
	}

	~Person()
	{
		delete[]name;
		cout << "called destructor!" << endl;
	}
};

int main(void)
{
	Person parr[3];		// 객체 기반 배열의 선언

	char namestr[100];
	char * strptr;
	int age;
	int len;

	for (int i = 0; i<3; i++)	// for문을 통해 이름, 나이 입력받아서 객체를 초기화
	{
		cout << "이름: ";
		cin >> namestr;
		cout << "나이: ";
		cin >> age;

		len = strlen(namestr) + 1;
		strptr = new char[len];						
		strcpy(strptr, namestr);
		parr[i].SetPersonInfo(strptr, age);
	}

	parr[0].ShowPersonInfo();
	parr[1].ShowPersonInfo();
	parr[2].ShowPersonInfo();

	return 0;
}


Output :

called Person()

called Person()

called Person()

이름: 가가가가가가

나이: 1

이름: 나나나나나나나나

나이: 2

이름: 다다다다다다다다다

나이: 3

이름: 가가가가가가, 나이: 1

이름: 나나나나나나나나, 나이: 2

이름: 다다다다다다다다다, 나이: 3

called destructor!

called destructor!

called destructor!



객체 포인터 배열

: 객체의 주소 값 저장이 가능한 포인터 변수로 이뤄진 배열

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

class Person
{
private:
	char * name;
	int age;
public:
	Person(char * myname, int myage)
	{
		int len = strlen(myname) + 1;
		name = new char[len];
		strcpy(name, myname);
		age = myage;
	}
	Person()
	{
		name = NULL;
		age = 0;
		cout << "called Person()" << endl;
	}
	void SetPersonInfo(char * myname, int myage)
	{
		name = myname;
		age = myage;
	}
	void ShowPersonInfo() const
	{
		cout << "이름: " << name << ", ";
		cout << "나이: " << age << endl;
	}
	~Person()
	{
		delete[]name;
		cout << "" << endl;		// 소멸자 호출과 delete 연산을 확인하기 위함
	}
};

int main(void)
{
	Person * parr[3];	// 객체 포인터 배열 선언

	char namestr[100];
	char * strptr;
	int age;
	int len;

	for (int i = 0; i < 3; i++)
	{
		cout << "이름: ";
		cin >> namestr;
		cout << "나이: ";
		cin >> age;

		parr[i] = new Person(namestr, age);	// 객체를 생성해, 주소값을 배열에 저장

	}
	cout << endl;
	for (int i = 0; i < 3; i++)
	{
		parr[i]->ShowPersonInfo();
		delete parr[i];		// new 연산을 한만큼 delete 연산 진행
	}

	return 0;
}

Output : 

이름: 가가가가

나이: 11

이름: 나나나나나나

나이: 22

이름: 다다다다다다다

나이: 33


이름: 가가가가, 나이: 11


이름: 나나나나나나, 나이: 22


이름: 다다다다다다다, 나이: 33




this 포인터의 이해

: 멤버 함수 내에서 객체 자신을 가리키는 용도로 사용되는 포인터


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

class SoSimple
{
	int num;
public:
	SoSimple(int n) : num(n)	// 생성자, 멤버 이니셜라이저 int num=n;
	{
		cout << "num=" << num << ", ";
		cout << "address=" << this << endl;
	}

	void ShowSimpleData()
	{
		cout << num << endl;
	}

	SoSimple * GetThisPointer()
	{
		return this;	
		// this를 반환. 이는 this가 가리키는 객체의 포인터를 반환하라는 의미로, 반환형이 SoSimple * 형 
	}
};

int main(void)
{
	SoSimple sim1(100);
	SoSimple * ptr1 = sim1.GetThisPointer();	// sim1 객체의 주소값을 * ptr1 에 저장	
	cout << ptr1 << ", ";		// ptr1에 저장된 주소값 출력
	ptr1->ShowSimpleData();		// ptr1이 가리키는 객체의 ShowSimpleData 함수 호출

	SoSimple sim2(200);
	SoSimple * ptr2 = sim2.GetThisPointer();
	cout << ptr2 << ", ";
	ptr2->ShowSimpleData();
	return 0;
}


Output:

1
2
3
4
num=100, address=0xffeb3708
0xffeb3708, 100
num=200, address=0xffeb3704
0xffeb3704, 200


this는 객체 자신을 가리키며, 위치한 객체내에서 자료형과 주소 값이 결정된다.

0xffeb3708에 할당된 sim1 객체 내에서는 this는 sim1 형의 포인터이면서 그 주소 값은 0xffeb3708 이 된다.



this 포인터 활용

객체의 주소 값으로 접근가능한 대상은 멤버 변수이다.

따라서 this->num1은 멤버 변수 num1을 의미한다.


위의 생성자는 아래의 같은 형태의 생성자로 대신할 수도 있다.


// this 포인터가 아닌 이니셜라이저를 통한 초기화 예

1
2
3
4
5
6
TwoNumber (int num1, int num2)
    : num1(num1), num2(num2)    
    // 이니셜라이저의 괄호안 num1은 매개변수 num1을 의미
{
    // empty
}
cs


멤버 이니셜라이저에서는 this포인터 사용불가. 



Self-Reference의 반환

: 객체 자신을 참조할 수 있는 참조자


#include <iostream>
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 &)이므로 객체 자신을 참조할 수 있는 참조자 반환
	}
	SelfRef& ShowTwoNumber()
	{
		cout << num << endl;
		return *this;
	}
};

int main(void)
{
	SelfRef obj(3);			
	obj.ShowTwoNumber();	
	SelfRef &ref = obj.Adder(2);	// 객체 obj의 참조값을 반환, 참조자 ref가 객체 obj의 참조자가 됨
	obj.ShowTwoNumber();
	ref.ShowTwoNumber();

	ref.Adder(1).ShowTwoNumber().Adder(2).ShowTwoNumber();
	return 0;
}


Output:

1
2
3
4
5
6
객체생성
3
5
5
6
8


this포인터를 이용해, 객체가 자신의 참조에 사용할 수 있는 참조자의 반환문을 구성 가능

34행에서  객체 ref의 Adder함수가 호출. Adder함수는 참조값을 반환하므로, 반환된 참조 값을 가지고 ShowTwoNumber 함수 호출이 가능하다.

마찬가지로 ShowTwoNumber가 반환하는 참조 값을 이용해 다시금 함수를 이어서 호출 할 수 있게 된다.


이는 두 함수 Adder, ShowTwoNumber가 객체의 참조 값을 반환하기 때문에 가능하다.



728x90