#include <malloc.h>
#include <iostream>
#include <exception>
#include <string>


struct A
{
	std::string s;

	A()
	{}

	virtual ~A()
	{}

	void * operator new (size_t s)
	{
		std::cout << "A::operator new: size=" << s << std::endl;
		return malloc( s );
	}

	void operator delete (void * p)
	{
		std::cout << "A::operator delete: p=" << p << std::endl;
		free(p);
	}
};

struct B : public A
{
	std::string b;
};

struct C : public A
{
	std::string c;
	
	void * operator new (size_t s)
	{
		std::cout << "C::operator new: size=" << s << std::endl;
		return malloc( s );
	}

	void operator delete (void * p)
	{
		std::cout << "C::operator delete: p=" << std::hex << p << std::endl;
		free(p);
	}
};

struct D : public B, public C
{
	//
	//	You should define this otherwise new/delete are ambiguous.
	//
	void * operator new (size_t s)
	{
		std::cout << "D::operator new: size=" << s << std::endl;
		return malloc( s );
	}

	void operator delete (void * p)
	{
		std::cout << "D::operator delete: p=" << std::hex << p << std::endl;
		free(p);
	}
};

struct F : public A
{
	std::string str;
};

struct E : public B, public F
{
};


void * operator new ( size_t s, const std::string& str )
{
	std::cout << str << std::endl;
	return malloc( s );
}


int main ( void )
{try{
	A * a;

	//
	//	Operator inheritance.
	//
	std::cout << std::hex << std::showbase << std::endl;
	std::cout << " Operator inheritance." << std::endl;
	std::cout << "===============================================" << std::endl;
	std::cout << "allocate and free A." << std::endl;
   	a = new A;
	delete a;
	
	std::cout << "allocate and free B." << std::endl;
   	a = new B;
	delete a;

	std::cout << "allocate and free C." << std::endl;
   	a = new C;
	delete a;

	std::cout << "allocate and free D." << std::endl;
	D * d = new D;
	std::cout << "D=" << d << " B=" << (B*)d << " C=" << (C*)d << std::endl;
   	a = (C*)d;
	delete a;

	std::cout << "allocate and free E." << std::endl;
   	E * e = new E;
	std::cout << "E=" << e 
			<< " B=" << (B*)e 
			<< " BA=" << (A*)(B*)e 
			<< " F=" << (F*)e 
			<< " FA=" << (A*)(F*)e << std::endl;
	a = (F*)e;
	delete a;

	//
	//	In place new.
	//
	std::cout << std::endl;
	std::cout << std::endl;
	std::cout << std::endl;
	std::cout << " In place new." << std::endl;
	std::cout << "===============================================" << std::endl;
	int * i = new (std::string("Hello")) int;

	std::cout << std::endl;
	std::cout << std::endl;
	return 0;
}
catch ( const std::exception& e )
{
	std::cerr << std::endl
			<< "std::exception(\"" << e.what() << "\")." << std::endl;
	return 2;
}
catch ( ... )
{
	std::cerr  << std::endl
			<< "unknown exception." << std::endl;
	return 1;
}}

