nullptr

기존에는 0과 NULL을 사용

void Test(int a)
{
	...
}

void Test(void* ptr)
{
	...
}

int main()
{
	Test(0);
	Test(NULL);
	Test(nullptr);
}

함수가 오버로딩 되어있을 경우 0이나 NULL을 사용하면 포인터를 활용할 때 문제가 생길 수 있음
즉, 위와 같은 경우 Test(0)Test(NULL)은 모두 int형을 매개변수로 하는 버전으로 작동함
반면 nullptr은 명확히 포인터 타입을 가리키기 때문에 Test(nullptr)void* 형을 매개변수로 하는 버전으로 작동함
또한 가독성 측면에서도 nullptr의 사용은 필수적임

class NullPtr
{
	public:
		//어떤 타입의 포인터와도 치환 가능
		template<typename T>
		operator T* () const
		{
			return 0;
		}
		// 어떤 타입의 멤버 포인터와도 치환 가능
		template<typename C, typename T>
		operator T C::* () const
		{
			return 0;
		}
	private:
		// 주소값 &을 막음
		vodi operator&() const;
};

using

typedef vector<int>::iterator Vecit;

typedef int id;
using id2 = int;

typedef void(*MyFunc)();
using MyFunc2 = void(*)();

template<typename T>
typedef std::vector<T> List; // 불가능함

template<typename T>
using List2 = std::list<T> // 가능함

usingtypedef보다 직관성이 좋음
usingtypedef와는 달리 템플릿을 이용할 수 있음
기본적으로 typedef보다 using이 모든 면에서 뛰어남


enum class

enum PlayerType
{
	PT_Knight,
	PT_Archer,
	PT_Mage
};

double value = PT_Knight;

enum의 경우 unscoped enum으로 enum에 설정되어있는 이름은 전역 사용 범위를 가지고있음
암묵적인 변환이 가능함

enum class ObjectType
{
	Player,
	Monster,
	Projectile
};

double value = ObjectType::Plyaer; // 불가능

enum class의 경우 scoped enum으로 설정되어있는 이름이 영역 안에서만 유효함
암묵적인 변환이 불가능함


delete (삭제된 함수)

class Knight
{
	public:
	
	private:
		void operator=(const Knight* k); // 사용은 가능하나 문제가있음
		void operator=(const Knight& k) = delete;
	private:
		int _hp = 100;
}

기존에는 사용하지 않는 함수를 private에 정의되지 않은 함수로 만들어줌
그러나 private에 정의하더라도 꺼내서 쓸 수 있는 경우가 발생할 수 있음
private에 선언한 함수의 구현부를 만들지 않을 시에는 함수의 사용을 방지할 수 있으나, 문제를 조기에 발견할 수 없음

함수 뒤에 = delete를 붙여줄 경우 더이상 사용하지 않을 함수라는 것을 확실하게 나타낼 수 있음


override, final

class Player
{
	public:
		virtual void Attack()
		{
			...
		}
};

class Knight : public Player
{
	public:
		// 재정의(override)
		virtual void Attack() override
		{
			...
		}
		// 오버로딩(overloading) : 함수 이름 재사용
		void Attack(int a)
		{
			...
		}
};

int main()
{
	Knight* knight = new Knight();
	knight->Attack();

	Player* player = new Knight();
	player->Attack();

	return 0;
}

virtual로 지정한 함수의 최초 사용이 어디였는지를 알 수 없음
따라서 재정의한 함수라는 것을 나타태기 위해 함수 뒤에 override 키워드를 붙여 사용할 수 있음

마지막으로 사용될 함수의 경우 final을 붙여 더이상 재정의되지 않도록 만들 수 있음