// G. Hagopian--PPP14 drill

/*
1. Define a class B1 with a virtual function vf() and a non-virtual function f(). 
Define both of these functions within class B1. Implement each function to output its name 
(e.g., B1::vf()). Make the functions public. Make a B1 object and call each function.
2. Derive a class D1 from B1 and override vf(). Make a D1 object and call vf() and f() for it.
3. Define a reference to B1 (a B1&) and initialize that to the D1 object you just defined. 
Call vf() and f() for that reference.
4. Now define a function called f() for D1 and repeat 1–3. Explain the results.
5. Add a pure virtual function called pvf() to B1 and try to repeat 1–4. Explain 
the result.
6. Define a class D2 derived from D1 and override pvf() in D2. Make an object of class D2 and
invoke f(), vf(), and pvf() for it.
7. Define a class B2 with a pure virtual function pvf(). Define a class D21 with a string data
member and a member function that overrides pvf(); D21::pvf() should output the value of the
string. Define a class D22 that is just like D21 except that its data member is an int. Define a
function f() that takes a B2& argument and calls pvf() for its argument. Call f() with a D21 and
a D22.
*/
#include<iostream>
#include <string>
using namespace std;

class B1 {
public:
	virtual void vf() { 
		cout << "B1::vf\n"; 
	}
	void f() { 
		cout << "B1::f\n"; 
	}
	virtual void pvf() = 0;
};

class D1 : public B1 {
public:
	virtual void vf() { cout << "D1::vf()\n"; } //overriding
	virtual void pvf() { cout << "D1::pvf()\n"; } //overriding pure virtual ftn
	void f() { cout << "D1::f()\n"; }
};

class D2 : public D1 {
public:
	virtual void pvf() { cout << "D2::pvf()\n"; } //overriding pure virtual ftn
};

class B2 {
public:
	virtual void pvf() = 0;
};

class D21 : public B2 {
public:
	string s = "oogabooga";
	virtual void pvf() { 
		cout << "D21::pvf"; 
		cout << "s = " << s;
	}
};

class D22 : public B2 {
public:
	int i = 12312451;
	virtual void pvf() {
		cout << "D22::pvf";
		cout << "i = " << i;
	}
	
};

void f(B2& b2) {
		b2.pvf();
}

int main() {
	//B1 b;  //can't instantiate abstract class
	D1 d;
	//b.vf(); //abstract class has no instance
	//b.f(); 
	/*
	B1::vf
	B1::f
	*/
	d.vf();
	d.f();
	d.pvf();
	/*
	D1::vf()
	D1::f()
	*/
	//B1& E1 = b; //alias for b, which, if B1 is pure, has no instance
	//E1.vf();
	//E1.f();
	/*
	B1::vf
	B1::f
	*/
	/*B1& F1 = d;
	F1.vf();
	F1.f();*/
	D2 d2;
	d2.f();
	d2.vf();
	d2.pvf();
	/*
	D1::f()
	D1::vf()
	D2::pvf()
	*/
	D21 d21;
	f(d21);
	D22 d22;
	f(d22);
	/*
	D21::pvf
	s = oogabooga
	D22::pvf
	i = 12312451
	*/
}

/*
B1::vf
B1::f
D1::vf()
D1::f()
B1::vf
B1::f
*/