반응형

중첩클래스는 말그대로 class의 class의 class의 class의 class다. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ (ㅈㅅ.. 근데 진짜임 ㅁㅊㅋㅋ)

이해를 돕기위한 사진을 보고 가시겠습니다...

아 미친 개웃기다

 

ㅈㅅ 이해를 돕기위한건 핑계고 그냥 이름 듣자마자 이거 생각나서 넣어봄.

사실 이번 주제는 하나도 어려운게 아니라 그냥 이런게 있다 하는 개념이라 뭐 별거없다.

그래서 이번 코드는 게임엔진 구조도 익힐 겸 실제로 사용하는 요소들을 넣어서 짜봤다.(Scene, Object, ObjectManager) ㅈㄴ 힘들었으니 개추부탁드립니다....

코드부터 바로 보고 시작하자.

#include <iostream>

class ObjectManager;

class Object
{
private:
	char* m_name;
public:

	Object(const char* _name)
	{
		m_name = new char[strlen(_name) + 1];
		strcpy_s(m_name, strlen(_name) + 1, _name);
	}

	~Object()
	{
		delete[] m_name;
	}

	char* GetName() 
	{
		return m_name;
	}
};



class Scene
{
private:
	// Scene에서만 쓸거면 Scene내부에 class를 만들어 준다. (근데 원래는 이러면 안댐 사실)
	class ObjectManager
	{
	private:

		Object* m_objectList[10]; // 걍 정적으로 선언헀지만 실제론 가변길이 컨테이너를 사용해야 한다능
		int size = 0;

	public:

		ObjectManager() = default;
		~ObjectManager() = default;

		Object* CreateObject(const char* _name)
		{
			Object* obj = new Object(_name);
			m_objectList[size++] = obj;
			return obj;
		}

		Object* GetObject(int _val)
		{
			return m_objectList[_val];
		}

		int GetObjectCount()
		{
			return size;
		}

	};

	ObjectManager* m_objectManager;

public:

	Scene()
	{
		m_objectManager = new ObjectManager();
	}
	~Scene()
	{
		delete m_objectManager;
	}

	ObjectManager* GetObjectManager() { return m_objectManager; }
	void Show()
	{
		std::cout << "Total ObjectCount : " << m_objectManager->GetObjectCount() << '\n';
		for (int i = 0; i < m_objectManager->GetObjectCount(); i++)
		{
			std::cout << i << "st Object : " << m_objectManager->GetObject(i)->GetName() << '\n';
		}
	}
};


int main()
{
	Scene myScene;
	myScene.GetObjectManager()->CreateObject("코딩이 즐겁다1");
	myScene.GetObjectManager()->CreateObject("코딩이 즐겁다2");
	myScene.GetObjectManager()->CreateObject("코딩이 즐겁다3");

	myScene.Show();

}

 

사실 그냥 클래스 안에 클래스나 struct를 짤 수 있다는 것만 알면 된다. 걍 심심해서 짜봄...

 


너무 대충 쓴 것 같아서 추가

 

list나 vector, stack 등과 같은 컨테이너의 iterator도 중첩클래스의 일부라고 보면 좋다.

STL - iterator — 개발자의 글쓰기 (tistory.com)

 

STL - iterator

컨테이너마다 내부 구조가 다른데, 이 컨테이너들을 하나의 연산으로 묶어서 순회할 수 있게 하는 것이 반복자다. 반복자의 종류 임의 접근 반복자, 양방향 반복자, 순방향 반복자, 입력 반복자,

blackmanta.tistory.com

이분거도 보면 class안에 struct, 혹은 class가 들어간다.

위 사진에서 예를 들면 NODE와 MyListIterator객체는 MyList의 내부에서 밖에 쓸 일이 없으므로 MyList안에 class를 구현한 것이다.

반응형

'프로그래밍 > C++' 카테고리의 다른 글

[C++] DFS 구현해보기  (0) 2024.07.10
[C++] operator 연산자  (0) 2024.06.14
[C++] friend에 대해 알아보자.araboza  (0) 2024.06.12
[C++] const, 근데 class를 곁들인  (0) 2024.06.11
[C++] static, 근데 class를 곁들인  (0) 2024.06.11
반응형

한국인을 위한 코드 미리보기

#include <iostream>

class MyClass
{

	int num = 0;

public:

	int Get() { return num; }
	void Set(int a) { num = a; }

	MyClass Sum1(MyClass obj)
	{
		MyClass temp;
		temp.Set(obj.Get() + this->Get());
		return temp;
	}
	friend MyClass Sum2(MyClass obj1, MyClass obj2);
};

MyClass Sum2(MyClass obj1, MyClass obj2)
{
	MyClass temp;
    // MyClass에서 friend 키워드를 주었기 때문에 private멤버에 접근이 가능한ww
	temp.num = obj1.num + obj2.num;
	return temp;
}

int main()
{

	MyClass x; x.Set(1);
	MyClass y; y.Set(2);

	MyClass z1 = x.Sum1(y);
	MyClass z2 = Sum2(x, y);

	std::cout << z1.Get() << " " << z2.Get();

	return 0;

}

 

미친 나도 친구가 없는데 class가 친구가 있네

 

friend 키워드를 통해 해당 함수에 자기의 private 멤버에 접근할 수 있다.

뭐야 ㅅㅂ 미친거아님?wwww 이라고 생각할 수도 있겠지만.... class의 캡슐화에 위배된다...라네요.

사실 저는 캡슐화 알빠노(물론 중요함. 하기 귀찮아서 그렇지) 라는 입장이기 때문에 별 생각 안들지만, 딱 보자마자 든 생각이.. 의존성이 너무 강해진다? 였다는 것.

(의존성이라는 것은 서로가 서로를 너무 의존해서 하나가 바뀌거나 없어지면 의존하던 코드도 같이 무너지는? 그런 느낌이라고 생각합니다. 사실 제 생각임 팩트인진 모름.)

 

어쨋든 friend 써보니까 매우 신세계긴 하네요. 하지만 안쓸듯. 일단 앞서 말했듯이 캡슐화를 위배하는 것도 있지만, 저는 그런거 알빠노고, 사실 의존성이 강해지는게 너무 맘에 걸리긴 한다는ww 추가적으로 friend를 남발하다 보면 여기저기서 멤버를 가져오기 때문에 그 유명한 스파게티코드가 될거 같다는? 느낌적인 느낌

 

그래도 연관성이 높은 객체끼리 쓰면 편의성이 아주 높아진다고 하니 감당가능하신 분들은 알아서 쓰시길.... 전 지능딸려서 남발하다가 나중에 유지보수를 못할 것 같아서 안쓸 것 같습니다 ㅅ_ㄱ...

 


20240907추가

friend..... 쓰는 날이 오긴 하더라.......

캡슐화를 위반하는 대신 은닉성을 좀 더 강화할 수 있어서 가끔 쓸거같습니다....

다만 남발하면 여전히 복잡해지고, 어쨋든 캡슐화를 위반하는거니 조심해서 써야 된다는 강박을 가지고 있는 중..

friend가 좋긴한데 너무 치트키 느낌이라 공부하는 입장에선 자제해서 써야겠습니다.

반응형
반응형

오늘 수업 들은것.... 근데 뭔가 글쓰기는 귀찮아서 주석으로 대체한다. (주석적다가 일부분 수업 놓침 망함티비)

#include <iostream>

class ConstTest
{
public:

	const int a = 0;
	int b = 0;

	ConstTest() {}
	~ConstTest() {}
	void Addnum()
	{
		b++;
	}
	int GetNum() const
	{
		return b;
	}
	void Show() const
	{
		std::cout << a << " " << b << '\n';
	}
};

int main()
{
	const ConstTest* a = new ConstTest(); // const객체 선언. 객체의 멤버를 바꾸지 않겠다!
	ConstTest* const b = new ConstTest(); // non-const객체 선언. 객체의 멤버를 바꿀 수 있다. but b포인터의 주소는 바꿀 수 없다.

	a->b += 1; // 에러. const객체는 멤버를 변경할 수 없다.
	b->b += 1; // 가능.

	a->Addnum(); // 에러. const객체는 const함수만 호출 가능.
	b->Addnum(); // 가능.

	a->GetNum() = 1; // const함수기 때문에 반환 값을 바꿀 수 없다.
	b->GetNum() = 1; // 위와 동일

	a->Show(); // 가능. const객체는 const함수는 호출할 수 있기 때문.
	b->Show(); // 가능.

	a = b; // 가능. 주소는 바꿀 수 있다. 멤버만 못바꿈.
	b = a; // 불가능. 포인터를 const화 시켰기 때문에 주소를 바꿀 수 없다.

	delete a;
	delete b;

	a = new ConstTest(); // 가능
	b = new ConstTest(); // 에러. const변수는 선언과 동시에 초기화 되어야 하기 때문

}

 

알아서들 이해하셨길....

반응형
반응형

하 개 오랜만에 글쓴다....

 

한국인을 위한 코드 미리보기

#include <iostream>

class Object
{
private:
	static int m_obejctCount;
	const char* m_name;
public:
	Object(const char* _name)
	{
		++m_obejctCount;
		m_name = _name;
		std::cout << "CreateObject (" << m_name << ")\n";
	}
	~Object()
	{
		--m_obejctCount;
		std::cout << "DeleteObject (" << m_name << ")\n";
	}
	static int GetObjectCount()
	{
		return m_obejctCount;
	}
	static void DestroyObject(Object* _target)
	{
		delete _target;
	}
};
int Object::m_obejctCount = 0;

int main()
{
	Object* a = new Object("Object1");
	Object* b = new Object("Object2");
	Object* c = new Object("Object3");

	Object::DestroyObject(c);

	std::cout << "Object Count : " << Object::GetObjectCount() << "\n";
}


먼저 알아가야 할 것..

밑줄  << 이렇게 밑줄 쫙 그어놓은건 ㅈㄴ 중요한거고

배경  << 이렇게 배경해놓은거는 그냥 한번 봤으면 좋겠다는 정도고

밑줄배경 << 이건 그냥 개 ㅈㄴ게 ㅁㅊ 레전드로 중요한거다 다른거 안봐도 이건 봐줍메 제발

class내에서 변수에 static을 붙였다 = 정적멤버변수

class내에서 함수에 static을 붙였다 = 정적멤버함수

(이게 ㅈㄴ게 중요!!!!!!) static은 전역변수, 함수 취급을 받는다. 하지만 class 내부에 멤버로 주게 될 경우 그냥 그 class 내부에서만 쓸 수 있게 한정해줄 뿐이다. 너무 어렵게 생각하지 말자... 첨에 이 개념을 못가져가서 많이 헷갈렸다.


static은 프로그램 시작시 할당되는데, 문제는 class객체의 생성 전에 할당된다는 것이다....

때문에 정적멤버변수는 class안에서 초기화를 못한다...(class 내부에서 해보고싶으면 해보자... 내 기억엔 에러뜸...)

따라서 정적멤버변수는 전역범위에서 따로 초기화를 해줘야 한다!!

이렇게...

 

그리고 위와 같은 이유로 멤버함수도 당연히 this포인터를 받지 못한다...

따라서 this->m_name과 같이 정적멤버함수는 비정적멤버변수에 접근하지 못한다.

근데 ㅈㄴ 웃긴게... 위에 사진처럼 정적멤버함수에 매개변수로 자신의 class를 자료형으로 줄 수 있음... 심지어 위에 사진에 있는 _target의 비정적멤버변수도 사용 가능. (이 순간 "아니 ㅅㅂ!! this는 못쓰는데 이건 어캐 씀?" 라는 의문을 가짐)

당연히 static은 프로그램 시작 시 할당되는데.... class의 존재여부를 모르는게 당연한거 아닌가? 해서 교수님한테 물어봄ㅋㅋ

교수님왈, 매개변수를 받아 쓰는건 초기화 이후의 과정이므로... 상관없다... 라는 느낌으로 말하셨는데 느낌만 알겠고 설명을 못하겠다...

 

자 여기까지 static의 멤버변수와 멤버함수에 대한 설명을 다 했다!  라고 하고싶은데 중요한게 하나 더 남아있음..ㅇㅇ

위에서 설명했지만 class내의 static도 전역변수,함수라고 생각하라고 했는데, 말 그대로 객체가 여러 개여도 정적 멤버는 하나밖에 존재할 수 없다.

따라서 위 사진에 a, b, c객체가 m_objectCount의 값을 공유한다는 것이다.

더 쉽게 말하면 그냥 m_objectCount라는 전역변수가 있는데, Object라는 class 내에서만 쓸 수 있는 것 뿐이다. 때문에 출력해보면 정적멤버변수인 ObjectCount가 생성(+1)-생성(+1)-생성(+1)-삭제(-1) = 2가 나오는 것이다!

 

하 적다보니 귀찮아서 그냥 대충 설명하게 된다... 알아서 잘 이해하셨길...

반응형

+ Recent posts