Hi,

I am writing a piece of code for a student database.
I have one abstract base class named student and three classes (physics student, biology student and chemistry student) derived from student.

I want to overload the insertion operator (<<) so that at some point in main I can print a students details to the screen.

Here is the code for how I have done it for my physics student class:

namespace phy_namespace{

class phy_student : public student{
protected:
	string name;
	int id;
	double av1;
	double av2;
	double av3;
	double course_av;
	vector<pair<double,string>> core_courses1;
	vector<pair<double,string>> core_courses2;
	vector<pair<double,string>> core_courses3;
	vector<pair<double,string>> option_courses1;
	vector<pair<double,string>> option_courses2;
	vector<pair<double,string>> option_courses3;
	pair<double,string> dissertation;
public:
	phy_student(string NAME, int ID) : name(NAME), id(ID), av1(0), av2(0), av3(0) {;}
	~phy_student() {;}
	void add_core_courses1();
	void add_core_courses2();
	void add_core_courses3();
	string get_name() {return name;}
	friend ostream & operator<<(ostream &cout, phy_student &student);
};
}

....................

ostream & phy_namespace::operator<<(ostream &cout, phy_student &student){
	cout<<"First year courses:"<<endl<<endl;
	vector<pair<double,string>>::iterator it;
	for(it=student.core_courses1.begin(); it!=student.core_courses1.end(); it++){
		cout<<"Course: "<<it->second<<" ("<<it->first<<" %)"<<endl;
	}
	return cout;
}

At the moment I am just trying to print out the students first year courses and corresponding grade. The courses and grades are stored in a vector of pairs.

My problem is this.

In main, my students are stored using a map, with their ID number as the identifier and a base class pointer as the second bit (I don't know what you call it).

i.e.

typedef map<int,student*> student_map;

In main I give the user the option to implement a search, which uses the following code:

void search(student_map &student, int ID){
	student_map::iterator it;
	it = student.find(ID);
	if(it != s.end()){
		cout<<"Found student with student number " << ID << ", his / her name is: "<<it->second->get_name()<<endl<<endl;
		cout<<*(it->second);
	}
	else cout<<"Sorry, there is no student number with student number " << ID <<" in database"<<endl;
}

However, the line:

cout<<*(it->second);

returns an error. I cannot see why because the iterator "it" points to whichever pair in the map that correspond to the ID number. Therefore "it->second" points to the base class pointer student, and dereferencing this should be the object itself, for which I have defined the overloaded insertion operator.

Any help would be greatly appreciated.

Thanks, Dave

Recommended Answers

All 3 Replies

Have you overloaded the operator for the base class? That is, do you have std::ostream & phy_namespace::operator<<( std::ostream &cout, const student& student); Also, do you know what virtual functions are?

I not overloaded the operator in the base class.
My base class "student" is the following:

class student{
public:
	virtual void add_core_courses1()=0;
	virtual void add_core_courses2()=0;
	virtual void add_core_courses3()=0;
	virtual void add_option_courses1()=0;
	virtual void add_option_courses2()=0;
	virtual void add_option_courses3()=0;
	virtual string get_name()=0;
};

Do you need to have a virtual function in the base class for all functions that are in derived classes?

My understanding of virtual functions is that since a base class pointer only points to the "base" part of a derived object, they are necessary to tell the compiler to look for the most derived version of a function.

Also, since I have put my three classes that are directly derived from student (each of these classes has another three derived from them) into their own namespaces, does that constitute a problem? i.e. can you have a base class in namespace std and different derived classes in their own namespaces?

Thanks, Dave

The base class with virtual functions (student) must have a virtual destructor.

Add an extra pure virtual function in the base class to handle stream output.

Override that function in derived classes to do class specific stream output.

Write a single overloaded operator for the base class to insert an object into a stream. As the object is passed by (const) reference, call to the virtual function will yield polymorphic stream output.

class student
{
    public:
        // a virtual destructor is required
        virtual ~student() {}

        // other virtual functions
        // virtual ... = 0 ;
        // etc.

        // add a virtual function to print to a stream
        virtual std::ostream& print( std::ostream& stm ) const = 0 ;
};

inline std::ostream& operator<< ( std::ostream& stm, const student& s )
{ return s.print(stm) ; } // print is dynamically dispatched  

class phy_student : public student
{
    std::ostream& print( std::ostream& stm ) const
    {
        // print out phy_student stuff
        // stm << ...
        return stm ;
    }

    // override other virtual functions

    // ...
};

> Do you need to have a virtual function in the base class for all functions that are in derived classes?

No.

> My understanding of virtual functions is that since a base class pointer only points to the "base" part of a derived object, they are necessary to tell the compiler to look for the most derived version of a function.

Yes.

> can you have a base class in namespace std and different derived classes in their own namespaces?

The base class need not be in the same namespace as a derived class. Each derived class could have its own namespace.

However, it is not a recommended practice to put your own stuff in namespace std.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.