#include <iostream>
using namespace std;

template <class T>
void out(T t) { cout << t << endl; }
void out(char *str) { cout << str << endl; }
template <class T>
void out(char *str, T t) { cout << str << ' ' << t << endl; }

class VirtualClass {
public:
	void virtual_func() { out("vir"); }
};

class PublicClass : public virtual VirtualClass {
private:
	void pub_private_func() {}
protected:
	void pub_protected_func() {}
public:
	void virtual_func() { out("pub"); }
	void pub_public_func() {}
	void override_fail_func() { out("pub"); }
	virtual void override_success_func() { out("pub"); }
	virtual void need_override_func() = 0;
};

class PrivateClass : public virtual VirtualClass  {
private:
	void prv_private_func();
protected:
	void prv_protected_func();
public:
	void virtual_func() { out("prv"); }
	void prv_public_func();
	PrivateClass(int x) {}
};

class ProtectedClass {
private:
	void prt_private_func();
protected:
	void prt_protected_func();
public:
	void prt_public_func();
};

class MyClass : public PublicClass, private PrivateClass,
                protected ProtectedClass, public virtual VirtualClass 
{
	friend class FriendClass;
	friend void friend_func(MyClass& mc);
private:
	static const int static_const_value;
	static int static_private_value;
	const int const_value;
	int private_value;
	void private_func();
	void func_access_prv() {
//		pub_private_func();   //NG
		pub_protected_func(); //OK
		pub_public_func();    //OK

//		prv_private_func();   //NG
		prv_protected_func(); //OK?
		prv_public_func();    //OK?

//		prt_private_func();   //NG
		prt_protected_func(); //OK?
		prt_public_func();    //OK?
	}
	void fa_prv() { func_access_prv(); } 
protected:
	int protected_value;
	void protected_func();
	void func_access_prt() {
//		pub_private_func();   //NG
		pub_protected_func(); //OK
		pub_public_func();    //OK

//		prv_private_func();   //NG
		prv_protected_func(); //OK?
		prv_public_func();    //OK?

//		prt_private_func();   //NG
		prt_protected_func(); //OK?
		prt_public_func();    //OK?
	}
	void fa_prt() { func_access_prt(); } 
public:
	MyClass();      //コンストラクタ
	MyClass(int x); //コンストラクタ(オーバーロード)
	MyClass(const MyClass& mc) : PrivateClass(5), const_value(mc.const_value) {
		private_value = MyClass::static_private_value++;
	}
	~MyClass();     //デストラクタ
	static void static_public_func();
	int public_value;
	void public_func();
	void virtual_func() { out("my"); }
	void override_fail_func() { out("my"); }
	void override_success_func() { out("my"); }
	void need_override_func() {}
	void const_ng_func() {}
	void const_ok_func() const {}
	inline int getPrivateValue() const {
		return private_value;
	}
	
	operator int() const {
		return const_value;
	}

	MyClass operator + (const MyClass& mc) {
		out("op+ l pv", private_value);
		out("op+ l cv", const_value);
		out("op+ r pv", mc.private_value);
		out("op+ r cv", mc.const_value);
		MyClass mc2(const_value + mc.const_value);
		out("op+ pv", mc2.private_value);
		out("op+ cv", mc2.const_value);
		return mc2;
	}
	
	void func_access_pub() {
//		func_access_prv();    //NG
//		func_access_prt();    //NG

//		pub_private_func();   //NG
		pub_protected_func(); //OK
		pub_public_func();    //OK

//		prv_private_func();   //NG
//		prv_protected_func(); //NG
//		prv_public_func();    //NG

//		prt_private_func();   //NG
//		prt_protected_func(); //NG
//		prt_public_func();    //NG
	}
};

const int MyClass::static_const_value = 123;
int MyClass::static_private_value = 1;

void MyClass::static_public_func() { out("spf"); }
void MyClass::private_func() {}
void MyClass::protected_func() {}
void MyClass::public_func() {}

MyClass::MyClass() : PrivateClass(1), const_value(1) {
	private_value = MyClass::static_private_value++;
}
MyClass::MyClass(int x) : PrivateClass(x * 2), const_value(x) {
	private_value = MyClass::static_private_value++;
}
MyClass::~MyClass() { out("des:", private_value); }

void friend_func(MyClass& mc) {
	mc.private_value = 777;
}

int main() {
	MyClass mc;
	MyClass mc1(123);
	const MyClass mc2(999);
	MyClass mc3 = 9876;
	MyClass *mc4 = new MyClass;      //動的割り当て
	MyClass *mc5 = new MyClass(789); //動的割り当て
	PublicClass *pub = &mc;     //OK
//	PrivateClass *prv = &mc;    //NG
//	ProtectedClass *prt = &mc;  //NG
	VirtualClass *vir = &mc;    //OK

	out("Public Value");
	out(mc.public_value = 333);

	out("Virtual Class.");
	pub->virtual_func(); //pub
	vir->virtual_func(); //vir
	mc.virtual_func();   //my
	mc.VirtualClass::virtual_func();   //vir
	mc.PublicClass::virtual_func();    //pub
//	mc.PrivateClass::virtual_func();   //NG
//	mc.ProtectedClass::virtual_func(); //NG


	out("Static Function");
	MyClass::static_public_func();
	
	out("Friend Function");
	friend_func(mc);
	
	out("Inline Function");
	out(mc.getPrivateValue());

	out("Override Fail Function");
	pub->override_fail_func();               //pub
	mc.override_fail_func();                 //my
	mc.PublicClass::override_fail_func();    //pub
	out("Override success Function");
	pub->override_success_func();            //my
	mc.override_success_func();              //my
	mc.PublicClass::override_success_func(); //pub
	
	out("Base Class");
//	mc.pub_private_func();   //NG
//	mc.pub_protected_func(); //NG
	mc.pub_public_func();    //OK

//	mc.prv_private_func();   //NG
//	mc.prv_protected_func(); //NG
//	mc.prv_public_func();    //NG

//	mc.prt_private_func();   //NG
//	mc.prt_protected_func(); //NG
//	mc.prt_public_func();    //NG
	
	out("Function Access");
	mc.func_access_pub();
	
	out("Override Operator");
	out("mc3 pv", mc3.getPrivateValue());
	out("mc3 cv", (int)mc3);
	MyClass mc6;
	out("mc6 pv", mc6.getPrivateValue());
	out("mc6 cv", (int)mc6);
	out(mc6 + mc3 + *mc5);

	out("Const Class");
//	mc2.const_ng_func();     //NG
	mc2.const_ok_func();     //OK
	
	out("delete.");
	delete mc4;
	delete mc5;
	out("deleted.");
	
	return 0;
}