Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++&C#] 공부 #25

Open
ggjae opened this issue Nov 5, 2021 · 8 comments
Open

[C++&C#] 공부 #25

ggjae opened this issue Nov 5, 2021 · 8 comments

Comments

@ggjae
Copy link
Owner

ggjae commented Nov 5, 2021

[C++&C#] 공부

@ggjae
Copy link
Owner Author

ggjae commented Nov 5, 2021

// 1. 일반 함수 포인터에 멤버 함수의 주소를 담을 수 없습니다.
// 2. 일반 함수 포인터에 static 멤버 함수의 주소를 담을 순 있습니다.

@ggjae
Copy link
Owner Author

ggjae commented Nov 5, 2021

class Dialog
{
public:
void Close(int) {} // 눈으로 보기에는 파라미터가 하나지? 사실은 두개야. Close(this, int)
static void Close2(int) {}
};

@ggjae
Copy link
Owner Author

ggjae commented Nov 5, 2021

// new의 정확한 동작 방식
// 1. 메모리를 먼저 할당하고
// 2. 생성자 호출

// delete
// 1. 소멸자 호출
// 2. 메모리 해지.

//	Point* p1 = new Point(1, 2); 대신
	// 1. 생성자 호출 없이 메모리만 할당하는 코드
	// 결국 operator new()는 malloc()의 C++ 버젼입니다.
	Point* p2 = static_cast<Point*>(operator new(sizeof(Point))); // -> 이게 곧 malloc에 대응하는 C++ 함수입니다.
	
	// 2. 이미 할당된 메모리에 객체 생성(생성자 호출 의미)
//	new Point(1, 2); // 새로운 메모리에 객체를 만들어 달라.
	new(p2) Point(1, 2); // p2라는 메모리 공간에 객체를 만들어 달라(생성자 호출해달라) 
	// 위치가 지정되어 있는 new라고 합니다. placement new

@ggjae
Copy link
Owner Author

ggjae commented Nov 5, 2021

int main()
{
	// 아래와 같은 코드가 있을때 
	// 메모리 할당 방식을 "malloc" or 다른 방식으로 변경하고 싶다.
	// 몇 군데를 수정해야 할까요? => 아래 네줄 모두 수정해야 함...
//	Point* p1 = new Point(1, 2);
//	delete p1;
//	Point* p2 = new Point(1, 2);
//	delete p2;
	// 메모리 할당 방식의 교체를 편리하게 하고 싶다.
	// 메모리 할당을 책임지는 클래스를 제공하자. => allocator

	std::allocator<Point> ax;
	// point 타입의 메모리 할당을 담당.
	// 표준 allocator는 operator new를 사용해요. 내부적으로.
	// 그러면, 내가 MyAlloc<Point> ax; 로 얼로케이터를 만들어주면 되잖아요 operator new로?

	//사용자 정의 allocator를 사용하면 메모리 할당 방식을 변경할 수 있다는 철학.
	Point* p1 = ax.allocate(1);
	
	ax.deallocate(p1, 1);
}

@ggjae
Copy link
Owner Author

ggjae commented Nov 5, 2021

#include <iostream>
#include <vector>
// 1. 각 도형을 타입화 하면 편리하다..
// 2. 모든 도형의 공통 기반 클래스가 있다면 모든 도형을 묶어서 관리할 수 있다.
// 3. 모든 도형의 공통의 특징은 반드시 기반 클래스에도 있어야 한다.
// => 그래야 기반 클래스 포인터로 묶어서 사용할 때 해당 특징을 쓸 수 있다.
// 4. 파생클래스가 재정의 하게 되는 함수는 반드시 가상함수
class Shape {
public:
	virtual void Draw() {
		std::cout << "Draw Shape" << std::endl;
	}
};

class Rect : public Shape{
public:
	void Draw() override { std::cout << "Draw Rect" << std::endl; }
};
// 에러가 나지 않게 override를 붙여주는거임. 기반클래스에도 있는지 본다구.. 오타내면 안되잖아.

class Circle : public Shape{
public:
	void Draw() { std::cout << "Draw Circle" << std::endl; }
};
int main()
{
	std::vector<Shape*> v; //Rect만 보관하는 컨테이너
	// 모든 도형의 공통 기반 클래스가 있으면, 묶으면 좋겠구나.
	// 파생클래스를 담을 수 있잖아.
	// 상속은 물려받을 떄 쓰지만, 묶을때도 써요.

	while (1) {
		int cmd;
		std::cin >> cmd;
		if (cmd == 1) {
			v.push_back(new Rect);
		}
		else if (cmd == 2) v.push_back(new Circle);
		else if (cmd == 9) {
			for (auto p : v) {
				p->Draw(); // p는 결국 shape인걸. shape에는 draw가 없는데 어떻게 해.
				// 방법 1 선택지는 p를 바로 쓰지 말고, rect나 circle로 캐스팅하자.
				// 하지만, 코드를 작성할때는 알 수 없잖아.
				// 방법 2. shape에 draw를 넣자.
				// 사각형도 그릴 수 있고, 원도 그릴 수 있잖아. 모든 도형 공통의 특징인 그린다는 사실은 반드시 shape에 있어야 해..
				// 묶었을 때 그 특징을 쓸 수 있다.
			}
		}
	}
}

@ggjae
Copy link
Owner Author

ggjae commented Nov 5, 2021

#include <iostream>
#include <vector>

// 5. OCP 원칙
// 기능 확장에는 열려 있고, (Open, Class나 모듈이 나중에 추가되어도)
// 코드 수정에는 닫혀있어야(Close, 기존 코드는 변경되지 않게)는 이론(principle)
// 개방 폐쇄의 법칙
// 객체 지향 원칙 중 5개의 원칙 SOLID : SRP, OCP, LSP, ISP, DIP를 알고 들어가야 함.

// 좋은 객체지향 코딩은 다섯개를 지키며 코딩하는거예요.
// 
// 6. 자주 사용되는 코딩 기술에 이름을 붙이자.
// 객체지향에서 널리 사용되는 코딩 스타일이 "이름"을 부여한 것
// 이게 ****************디자인 패턴**********.

class Shape {
public:
	int type;
	virtual void Draw() {
		std::cout << "Draw Shape" << std::endl;
	}
	// 자신의 복제본을 만드는 가상함수는 항상 유용하게 활용됩니다.
	virtual Shape* Clone() { return new Shape(*this); }
};

class Rect : public Shape {
public:
	void Draw() override { std::cout << "Draw Rect" << std::endl; }
	Shape* Clone() override { return new Rect(*this); }
};


class Circle : public Shape {
public:
	void Draw() { std::cout << "Draw Circle" << std::endl; }
	Shape* Clone() { return new Circle(*this); }
};
class Triangle : public Shape {
public:
	void Draw() { std::cout << "Draw Triangle" << std::endl; }
};
int main()
{
	std::vector<Shape*> v;

	while (1) {
		int cmd;
		std::cin >> cmd;
		if (cmd == 1) {
			v.push_back(new Rect);
		}
		else if (cmd == 2) v.push_back(new Circle);
		else if (cmd == 8) {
			std::cout << "몇번째 도형을 복사할래요";
			int k;
			std::cin >> k;
			// k번째 도형의 복사본을 만들어 v에 추가합시다.
			// k번째 도형은 뭘까요?
			// 어떻게 해야할까요?
			/* 아래는 OCP를 만족하지 못하는 전형적 코드
			switch (v[k]->type) {
			case 1: v.push_back(new Rect(*v[k])); break;
			case 2: v.push_back(new Circle(*v[k])); break;
			}
			*/
			// 리팩토링 용어
			// Replace Conditional with Polymorphism
			// 조건문을 다형성(가상함수)으로 변경해라.

			v.push_back(v[k]->Clone()); // 다형성. OCP 만족 좋은 코드
		}
		else if (cmd == 9) {
			for (auto p : v) {
				p->Draw(); // 상황에 따라 달라지는걸 뭐라 부르죠? 다형성 (polymorphism)
				// 동일한 함수 호출 코드가 상황에 따라 다르게 동작하는 것
				// 다형성의 장점이 뭐에요?
				// 나중에 추가된 트라이앵글 클래스도, 이 38번째줄의 라인은 바뀔 필요가 없죠?
				// 기능이 확장되어도, 코드에는 닫혀있어야한다.
			}
		}
	}
}

@ggjae
Copy link
Owner Author

ggjae commented Nov 5, 2021

C++11 final : 파생클래스가 재정의 못하게 하는 문법

@ggjae
Copy link
Owner Author

ggjae commented Nov 5, 2021

한 언어를 공부할 땐, 최상위 클래스를 확인하자. => C#이라면 object가 어떻게 구성되어 있는지, 멤버함수가 어떻게 구성되어 있는지!!!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant