#include <iostream>
#include <cmath> // for std::pow
#include <vector>

class mean{
public:
	mean(){};
	virtual ~mean(){};
	virtual mean & add_data(int d) = 0;
	virtual double get_mean() const =0;
	virtual void print(std::ostream & o=std::cout) const =0;
private:
	mean(const mean & a) = default;
	mean & operator=(const mean & a) = default;

};

class arithmetic:public mean{
public:
	arithmetic(): ncount_{0}, rsum_{0}, amean_{0} {};

	// Use Relaxation return type, the covariant rule
	arithmetic & add_data(int d) override { *this+=d; return *this; }

	arithmetic & operator+=(int d){
		rsum_+=d;
		ncount_++;
		double stemp=static_cast<double>(rsum_);
		double ntemp=static_cast<double>(ncount_);
		amean_=stemp/ntemp;
		return *this;
	}

	double get_mean() const override { return amean_;}
	void print(std::ostream &o) const override {
		std::cout << " Arithmetic mean: " << get_mean() << std::endl;
	}

private:
	int ncount_;
	int rsum_;
	double amean_;
};

class geometric:public mean{
public:
	geometric(): ncount_{0}, rproduct_{1}, gmean_{0} {};

	// Use Relaxation return type, the covariant rule
	geometric & add_data(int d){ *this*=d; return *this; }

	geometric & operator*=(int d){
		rproduct_*=d;
		ncount_++;
		double ptemp=static_cast<double>(rproduct_);
		double ntemp=static_cast<double>(ncount_);
		gmean_=std::pow(ptemp,1.0/ntemp);
		return *this;
	}

	double get_mean() const { return gmean_;}
	void print(std::ostream &o) const override {
		std::cout << " Geometrical mean: " << get_mean() << std::endl;
	}

private:
	int ncount_;
	int rproduct_;
	double gmean_;

};

int main(){

	arithmetic a;
	geometric b;
	std::vector<mean*> means;
	means.push_back(&a);
	means.push_back(&b);
	int indata{0};
	std::cout <<"Enter values [Ctrl-D to finish]: " <<std::endl;

	while(std::cin>>indata){
		//    a+=indata;
		//    b*=indata;
		for(auto i: means) i->add_data(indata);
	}

	for(const auto i: means) i->print();//	for(std::vector<mean*>::const_iterator i=means.begin(); i!= means.end(); ++i) (*i)->print();

	return 0;
}