namespace bad
{
	class Data // always initializes its members, leaves no choice to the client code :(
	{
	private:
	    int   _i;
	    float _f;
	    void* _p;

	public:
	    Data() : _i(0), _f(0.f), _p(nullptr) { }
	    
	    void SetI(int   value) { _i = value; }
	    void SetF(float value) { _f = value; }
	    void SetP(void* value) { _p = value; }
	    
	    double GetSomethingMeaningful() const { return !_p ? (_f * _i) : *(double*)_p; }
	};
}

namespace good
{
	class BasicData // base class for DataSafe and DataFast
	{
	protected:
	    int   _i;
	    float _f;
	    void* _p;

	protected:
	    BasicData() = default; // no initialization, leaves moosor!
	    BasicData(int i, float f, void* p) : _i(i), _f(f), _p(p) { }

	public:
	    void SetI(int   value) { _i = value; }
	    void SetF(float value) { _f = value; }
	    void SetP(void* value) { _p = value; }

	    double GetSomethingMeaningful() const { return !_p ? (_f * _i) : *(double*)_p; }
	};
	
	class DataSafe : public BasicData // always initializes its members
	{
	public:
		DataSafe() : BasicData(0, 0.f, nullptr) { }
	};
	
	class DataFast : public BasicData // no implicit members' initialization
	{
	};
}

#include <iostream>
using std::cout;

int main()
{
	double d = 42.0;
	void* pd = (void*)&d;
	
	{
	    bad::Data obj;
	    obj.SetI(2);
	    obj.SetF(3.14);
	    cout << obj.GetSomethingMeaningful() << '\n';
	}
	
	{
	    good::DataSafe obj;
	    obj.SetF(3.14);
	    cout << obj.GetSomethingMeaningful() << '\n';
	}
	
	{
	    good::DataFast obj;
	    obj.SetP(pd);
	    cout << obj.GetSomethingMeaningful() << '\n';
	}
}
