//Experiment with virtual functions //Disclaimer... the rules embodies rules have selected because they are // interesting to develop not necesarily because they are desirable, // ethical, or real in the authors opinion. If you want to change them // it makes a useful exercise.... do it. #include #include #include typedef char* string; const string UNKNOWN="Unknown"; class Date{ // worry about this later! int julian; public: Date(int j){julian=j;} Date(){julian=0;} };//Date enum Gender{UNKNOWN_GENDER=0, MALE = 1, FEMALE = 2}; // Persons are either Male or Female. class Female; class Male; class Person { protected: // allows restricted acces by Females and Males to following data Date m_dob; char * m_name; Person * m_spouse, *m_sib; Female * m_mother; //Notice! No m_gender data. private: void new_Person(string name=UNKNOWN, Date dob=Date(0), Female* mother=0) { m_name = new char [strlen(name)+1]; strcpy( m_name, name ); m_mother=mother; m_dob=dob; m_spouse=m_sib=0; } public: virtual Gender gender(){return UNKNOWN_GENDER;} virtual Person * child(){return 0;}; Person(){new_Person();} Person(string name){new_Person(name);} Person(string name, Date dob){new_Person(name,dob);} Person(string name, Date dob, Female* mother) {new_Person(name,dob,mother);} //Person(string name, Date dob, Female* mother, Gender gender); // the above must make a new Male or Female, but constructors can // not be called... Date dob(){return m_dob;} string name(){return m_name;} Female* mother(){ return m_mother;} // 0 when mother unknown // Below: 0 if none Person* spouse(){ return m_spouse;} Person* sib(){ return m_sib;} Person* youngest_child() { Person* child=this-> child(); if(!child)return 0; for( Person* nxt = child-> m_sib; nxt ; nxt = nxt -> m_sib ) child = nxt; return child; } Person* elder_sib(); //Destructor ~Person(){ delete m_name; } //because each person looks after the storage for its own name //Loophole. Can not safely copy Person,Male, Female. //Todo: Add copy constructor and assignment. //events in the life of a person void gets_a_sibling(Person* p){m_sib=p;} // I'd prefer for this to be protected. void marries( Person* p) { this-> m_spouse=p; p-> m_spouse=this; } void divorces(Person* p) { this-> m_spouse=0; p-> m_spouse=0; } void unmarried() { this-> m_spouse = 0; } }; class Male: public Person { public: void adopts(Person* p); Gender gender(){return MALE;} Person* child(); //Constructors Male(string name):Person(name){ } Male(string name, Date dob, Female* mother):Person(name,dob,mother) { } Male():Person(){} }; class Female: public Person { Person * m_child;//first child if any public: Gender gender(){return FEMALE;} Person* child(); //Constructors Female(string name):Person(name){ m_child=0; } Female(string name, Date dob, Female* mother): Person(name,dob,mother){ m_child=0; } Female():Person(){m_child=0;} void adopts(Person * p) { if(m_child) ( youngest_child() ) ->gets_a_sibling(p); else m_child = p; } void gives_birth_to(string name, Gender gender, Date dob) { Person* baby; switch(gender) { case MALE: baby = new Male(name,dob,this); break; case FEMALE: baby = new Female(name,dob,this); break; default: baby = new Person(name,dob,this); } if(!baby) { cerr << "Unable to allocate more memory\n"; exit(EXIT_FAILURE); //exercise -- replace by exception } this->adopts(baby); } };//end class Female void Male::adopts(Person* p) { if(m_spouse) ((Female*)m_spouse)->adopts(p); else { cerr<<"Unmarried males don't adopt children\n";exit(2); } } Person* Female::child(){return m_child;} Person* Male::child(){return m_spouse->child();} Person* Person::elder_sib() { Female* my_mother=this-> mother(); if(!my_mother)return 0; Person* child=my_mother->child(); if(!child)return 0; for( Person* nxt = child-> m_sib; nxt != this ; nxt = nxt -> m_sib ) child = nxt; return child; } int main() { Male owen("Owen"); Female maureen("Maureen"); owen.marries( &maureen); maureen.gives_birth_to("Kathleen", FEMALE, Date(0)); maureen.gives_birth_to("Kaitlin", FEMALE, Date(0)); cout << owen.child()->name() << endl; cout << owen.youngest_child()->name() << endl; return 0; }