티스토리 뷰

주의 사항!

  • 이 글은 제가 직접 공부하는 중에 작성되고 있습니다.
  • 따라서 제가 이해하는 그대로의 내용이 포함됩니다.
  • 따라서 이 글은 사실과는 다른 내용이 포함될 수 있습니다.

 

객체 배열

객체 배열과 객체 포인터 배열은 C언어를 공부하면서 다루었던 구조체 배열, 구조체 포인터 배열과 유사합니다.

 

객체 배열은 다음의 형태로 선언합니다.

SoSimple arr[10];    //SoSimple은 클래스명

 

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

SoSimple * ptrArr = new SoSimple[10];

 

객체 배열을 선언할 때는 주의해야 할 점이 있습니다. 앞서 객체를 생성하면 반드시 하나의 생성자가 호출이 되어야 한다고 했습니다. 이는 객체 배열에 대해서도 마찬가지입니다. 단, 객체 배열의 선언에서는 생성자에 인자를 전달하지 못합니다. 즉, 객체 배열이 생성되려면 다음 형태의 생성자가 반드시 정의되어 있어야 합니다.

SoSimple() {...}

 

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

 

여기서 궁금한 점 하나.

객체를 생성할 때 생성자를 별도로 만들지 않으면, 컴파일 과정에서 디폴트 생성자를 자동으로 삽입했다. 이는 객체 배열을 선언할 때에는 해당되지 않는가? 매개변수가 없는 생성자가 필요하다면, 하지만 그런 생성자가 없다면, 디폴트 생성자를 삽입하는 것도 하나의 방법이 될 텐데 아직 이 책에서는 이에 대한 내용이 없다.

 

다음 예제를 통해 객체 배열에 관해 알아보겠습니다.

#include <iostream>
#include <cstring>

using std::cout;
using std::cin;
using std::endl;

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

public:
	Person(const char* myName, int myAge)
	{
		name = new char[strlen(myName) + 1];
		strcpy(name, myName);

		age = myAge;
	}

	Person()
	{
		name = NULL;
		age = 0;
		cout << "called constructor." << endl;
	}

	void SetPersonInfo(char* myName, int myAge)
	{
		name = myName;
		age = myAge;
	}

	void ShowPersonInfo(void) const
	{
		cout << "이름 : " << name << ", 나이 : " << age << endl;
	}

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

int main(void)
{
	Person pArr[3];
	char nameStr[100];
	char* pName;
	int age;
	
	for (int i = 0; i < 3; i++)
	{
		cout << "이름 : ";
		cin >> nameStr;
		cout << "나이 : ";
		cin >> age;
		pName = new char[strlen(nameStr) + 1];
		strcpy(pName, nameStr);
		pArr[i].SetPersonInfo(pName, age);
	}

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

	return 0;
}

/*
실행결과

called constructor.
called constructor.
called constructor.
이름 : KOEY
나이 : 19
이름 : 홍길동
나이 : 56
이름 : 임진왜란
나이 : 12
이름 : KOEY, 나이 : 19
이름 : 홍길동, 나이 : 56
이름 : 임진왜란, 나이 : 12
called destructor.
called destructor.
called destructor.

*/

 

위의 예제에서 Person 클래스의 객체를 배열로 선언했기 때문에 매개 변수를 받지 않는 생성자가 호출되었습니다.

 

그런데 저는 이런 생성자가 아예 없는 경우, 객체 배열을 선언한 경우에도 디폴트 생성자가 삽입될 것인가를 확인하고 싶었습니다. 결과는 다음과 같았습니다.

#include <iostream>
#include <cstring>

using std::cout;
using std::cin;
using std::endl;

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

public:
	/*
	Person(const char* myName, int myAge)
	{
		name = new char[strlen(myName) + 1];
		strcpy(name, myName);

		age = myAge;
	}

	Person()
	{
		name = NULL;
		age = 0;
		cout << "called constructor." << endl;
	}
	*/

	void SetPersonInfo(char* myName, int myAge)
	{
		name = myName;
		age = myAge;
	}

	void ShowPersonInfo(void) const
	{
		cout << "이름 : " << name << ", 나이 : " << age << endl;
	}

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

int main(void)
{
	Person pArr[3];
	char nameStr[100];
	char* pName;
	int age;
	
	for (int i = 0; i < 3; i++)
	{
		cout << "이름 : ";
		cin >> nameStr;
		cout << "나이 : ";
		cin >> age;
		pName = new char[strlen(nameStr) + 1];
		strcpy(pName, nameStr);
		pArr[i].SetPersonInfo(pName, age);
	}

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

	return 0;
}

/*
실행결과

이름 : KOEY
나이 : 23
이름 : 홍길동
나이 : 56
이름 : 임진록
나이 : 12
이름 : KOEY, 나이 : 23
이름 : 홍길동, 나이 : 56
이름 : 임진록, 나이 : 12
called destructor.
called destructor.
called destructor.

*/

 

생성자가 없는 객체 배열을 선언해도 디폴트 생성자가 자동으로 삽입되는 듯합니다.

 

객체 포인터 배열

다음은 객체 포인터 배열에 관한 예제입니다.

#include <iostream>
#include <cstring>

using std::cout;
using std::cin;
using std::endl;

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

public:
	Person(char* myName, int myAge)
	{
		name = new char[strlen(myName) + 1];
		strcpy(name, myName);

		age = myAge;
	}

	Person()
	{
		name = NULL;
		age = 0;
		cout << "called constructor." << endl;
	}

	void SetPersonInfo(char* myName, int myAge)
	{
		name = myName;
		age = myAge;
	}

	void ShowPersonInfo(void) const
	{
		cout << "이름 : " << name << ", 나이 : " << age << endl;
	}

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

int main(void)
{
	Person *pArr[3];
	char nameStr[100];
	int age;
	
	for (int i = 0; i < 3; i++)
	{
		cout << "이름 : ";
		cin >> nameStr;
		cout << "나이 : ";
		cin >> age;
		pArr[i] = new Person(nameStr, age);
	}

	pArr[0]->ShowPersonInfo();
	pArr[1]->ShowPersonInfo();
	pArr[2]->ShowPersonInfo();

	delete pArr[0];
	delete pArr[1];
	delete pArr[2];

	return 0;
}

/*
실행결과

이름 : KOEY
나이 : 24
이름 : 유관순
나이 : 74
이름 : 양동근
나이 : 1563
이름 : KOEY, 나이 : 24
이름 : 유관순, 나이 : 74
이름 : 양동근, 나이 : 1563
called destructor.
called destructor.
called destructor.

*/

 

객체 포인터 배열을 사용하니 객체 선언과 동시에 초기화까지 유용함을 알 수 있었습니다.

 

this 포인터

멤버 함수 내에서는 this라는 이름의 포인터를 사용할 수 있는데 이는 객체 자신을 가리키는 용도로 사용되는 포인터입니다. 간단한 예제를 통해 this 포인터에 관해 알아보겠습니다.

#include <iostream>
#include <cstring>

using std::cout;
using std::cin;
using std::endl;

class SoSimple
{
private:
	int num;

public:
	SoSimple(int n) : num(n)
	{
		cout << "num = " << num << ", address  = " << this << endl;
	}

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

	SoSimple* GetThisPointer()
	{
		return this;
	}
};

int main(void)
{
	SoSimple sim1(100);
	SoSimple* ptr1 = sim1.GetThisPointer();
	cout << ptr1 << ", ";
	ptr1->ShowSimpleData();

	return 0;
}

/*
실행결과

num = 100, address  = 00FDFC10
00FDFC10, 100

*/

 

이 예제만 보아도 this 포인터의 정체를 파악할 수 있을 것입니다.

 

self-reference

Self-Reference란 객체 자신을 참조할 수 있는 참조자를 의미합니다. this포인터를 이용하면 객체가 자신의 참조에 사용할 수 있는 참조자의 반환문을 구성할 수 있습니다. 다음 예제를 보겠습니다.

#include <iostream>

using std::cout;
using std::cin;
using std::endl;

class SelfRef
{
private:
	int num;

public:
	SelfRef(int n) : num(n)
	{
		cout << "객체 생성" << endl;
	}

	SelfRef& Adder(int n)
	{
		num += n;

		return *this;
	}

	SelfRef& ShowNumber(void)
	{
		cout << num << endl;

		return *this;
	}
};

int main(void)
{
	SelfRef obj(3);
	SelfRef& ref = obj.Adder(2);

	obj.ShowNumber();
	ref.ShowNumber();

	ref.Adder(1).ShowNumber().Adder(2).ShowNumber();

	return 0;
}

/*
실행결과

객체 생성
5
5
6
8

*/

 

this 포인터를 간접 참조하여 참조형으로 반환하고, 이를 참조자가 참조하는 것은 어려운 개념은 아닙니다. 흥미로운 부분은 Adder 함수와 ShowNumber 함수가 자기 자신을 참조하는 참조자를 반환하기 때문에 main 함수 마지막 줄 즈음과 같이 Adder 함수와 ShowNumber 함수를 쭉 연달아 호출할 수 있다는 것입니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함