Vectors of Classes

Started by
7 comments, last by Zahlman 16 years, 11 months ago
I want to create a vector of the class that I am working with. I can currently successfully create an array with the class, but I am having troubles with the vector class. Here is the code that I have so far:




#include <string>
#include <vector>
#include <iostream>

using namespace std;

//////////////////////////////////////////////////////////////////
// R E F E R E N C E  C L A S S                             ****//
//////////////////////////////////////////////////////////////////

class Reference                                                 // Parent
{
	private:
		//declare all variables
		string Author, Title, Journal, Year, Volume, Number, Pages, Note;
		string Key, Booktitle, Editor, Organisation, Publisher, Address, Month;
		string Series, Edition, Institution, Type, Howpublished;
		string ReferenceType;
	public:
		Reference(string refType)
		{
			ReferenceType = refType;
		}
		
		//set functions
		void setAuthor(string author);
		void setTitle(string title); 
		void setJournal(string journal); 
		void setYear(string year); 
		void setVolume(string volume); 
		void setNumber(string number);
		void setPages(string pages);
		void setNote(string note);
		void setKey(string key);
		void setBooktitle(string booktitle);
		void setEditor(string editor);
		void setOrganisation(string organisation);
		void setPublisher(string publisher);
		void setAddress(string address);
		void setMonth(string month);
		void setSeries(string series);
		void setEdition(string edition);
		void setInstitution(string institution);
		void setType(string type);
		void setHowpublished(string howpublished);
		
		//get functions
		string getAuthor();
		string getTitle();
		string getJournal();
		string getYear();
		string getVolume();
		string getNumber();
		string getPages();
		string getNote();
		string getKey();
		string getBooktitle();
		string getEditor();
		string getOrganisation();
		string getPublisher();
		string getAddress();
		string getMonth();
		string getSeries();
		string getEdition();
		string getInstitution();
		string getType();
		string getHowpublished();
		
		string ReturnReference();
			

}; 

//set functions
void Reference::setAuthor(string author) {Author = author;}
void Reference::setTitle(string title) {Title = title;}
void Reference::setJournal(string journal) {Journal = journal;}
void Reference::setYear(string year) {Year = year;}
void Reference::setVolume(string volume) {Volume = volume;}
void Reference::setNumber(string number) {Number = number;}
void Reference::setPages(string pages) {Pages = pages;}
void Reference::setNote(string note) {Note = note;}
void Reference::setKey(string key) {Key = key;}
void Reference::setBooktitle(string booktitle) {Booktitle = booktitle;}
void Reference::setEditor(string editor) {Editor = editor;}
void Reference::setOrganisation(string organisation) {Organisation = organisation;}
void Reference::setPublisher(string publisher) {Publisher = publisher;}
void Reference::setAddress(string address) {Address = address;}
void Reference::setMonth(string month) {Month = month;}
void Reference::setSeries(string series) {Series = series;}
void Reference::setEdition(string edition) {Edition = edition;}
void Reference::setInstitution(string institution) {Institution = institution;}
void Reference::setType(string type) {Type = type;}
void Reference::setHowpublished(string howpublished) {Howpublished = howpublished;}


//get funcitons
string Reference::getAuthor() {return Author;}
string Reference::getTitle() {return Title;}
string Reference::getJournal() {return Journal;}
string Reference::getYear() {return Year;}
string Reference::getVolume() {return Volume;}
string Reference::getNumber() {return Number;}
string Reference::getPages() {return Pages;}
string Reference::getNote() {return Note;}
string Reference::getKey() {return Key;}
string Reference::getBooktitle() {return Booktitle;}
string Reference::getEditor() {return Editor;}
string Reference::getOrganisation() {return Organisation;}
string Reference::getPublisher() {return Publisher;}
string Reference::getAddress() {return Address;}
string Reference::getMonth() {return Month;}
string Reference::getSeries() {return Series;}
string Reference::getEdition() {return Edition;}
string Reference::getInstitution() {return Institution;}
string Reference::getType() {return Type;}
string Reference::getHowpublished() {return Howpublished;}

string Reference::ReturnReference()
{
	if (ReferenceType == "Book")
	{
		//output book reference
		string tempRef;
		string tempYear;
		string tempEd;
		string tempVol;
		string tempEdVol="";
		string tempPub;
		
		if (Year != "") //if the year exists, include it
		{
			tempYear = "(" + Year + ").";
		}
		
		if (Edition != "") //check if edition exists
		{
			tempEd = Edition + " ed.";
		}
		
		if (Volume != "") //check if volume exists
		{
			tempVol = "Vol " + Volume + ".";
		}
		
		if ((Volume != "") && (Edition != "")) //if they both exist
		{
			tempEdVol = "(" + tempEd + " " + tempVol + ").";
		}
		
		if ((Volume ==  "") && (Edition != "")) //just edition exists
		{
			tempEdVol = "(" + tempEd + ").";
		}
		
		if ((Volume != "") && (Edition == "")) //just volume exists
		{
			tempEdVol = "(" + tempVol + ").";
		}
		
		if (Publisher != "") {tempPub = ":" + Publisher;}
		
		
		tempRef = Author + " " + tempYear + " " + Title + " " + tempEdVol + " " + Address + tempPub;
		
		return tempRef;
	}
	
}



int main()
{

	
	//Reference aBook("Book");
	
	//aBook.setAuthor("Daniel Beard");
	//aBook.setTitle("This is the title");
	//aBook.setYear("1999");
	//aBook.setEdition("Fifth");
	//aBook.setVolume("3");
	//aBook.setPublisher("Cheese Publishing");
	//aBook.setAddress("Perth");
	
	vector<Reference> ref;
	int i;
	i = 1;
	
	ref.push_back("Book");
	ref.setAuthor("Daniel");
	ref.setTitle("This is a title");
	ref.setYear("1999");
	
	//cout << aBook.ReturnReference() << endl;
	cout << ref.ReturnReference() << endl;


}


The commented out code is the code that works, however, I would prefer to be using vectors rather than arrays, so I tried to create new vectors of the class. The above code gives a compile error : /Users/dan/Desktop/New Reference Class/main.cp:194: error: no matching function for call to 'std::vector<Reference, std::allocator<Reference> >::push_back(const char [5])' How would I call a new vector of the Reference class? Thanks, Dan
Advertisement
ref.push_back(Reference("Book"));


You are attempting to add a C-style string onto a vector of Reference objects, which won't work. First you need to construct a Reference object from the string. Also, you'll run into problems if you don't have a copy constructor and assignment operator:

Reference (const Reference &ref){    //Copy ref's class variables    ...}Reference &operator= (const Reference &ref){    //Set class variables    ...    return *this;}
strtok already answered the biggest issue with what you're asking, but also wanted to add a quick note. Vector element indexing starts with 0, like arrays, so you'll want to be careful with that. Above, the first push_back would put the first object at element[0], so an attempt to access members at element[1] wouldn't work until a second push_back occured.

Scorp
Why do I need to copy the ref class variables?
There is only one class, the Reference class, and what does the operator function do?
I don't really understand what I have to put in those two functions that you suggested to add.

Thanks
Dan
I would be best leaving the copy method for someone else to explain correctly, but as far as the assignment operator function, I'll take a stab at that one.

If you have two different int variables, foo and bar, it's easy to simply code "foo = bar;". That's because the data type implementation has the necessary code already there to take the value of bar and store it into foo.

With a custom data type, the Reference class in this case, that code doesn't exist, because it's your own data type. By adding that class method, it gives you the same type of functionality as described with the int variables, only with your class objects instead.

If you're wondering where it might be useful, anytime you have the need to simply say "Reference A = Reference B", your class knows how to make that happen, by assigning all of the class members the correct values. Otherwise, if you try to do that with a custom data type, your compiler is going to complain, saying that it cannot find any operator function.

Hope that makes some sense :)
Scorp
I changed the line to ref.push_back(Reference("Book"));
Now I am getting the error:

New Reference Class has exited due to signal 11 (SIGSEGV).

Can anyone help me, I don't know what to put in the copy constructor or the operator overloading.

Thanks
Dan
Did you change the int i to 0 instead of 1? I mentioned earlier about vectors being 0-based, which one needs to be careful of. I'm only asking that because the code as it is, with that exception and
ref.push_back(Reference("Book"));

it compiles and runs fine for me.

As far as what will go in the other two functions, I honestly don't know if I would worry about that a ton at this time, because your class doesn't have any members that require dynamic memory allocation. With that, the defaults it will run with may work ok. If not, then tackle those. But for now, try changing how you're indexing the vector array and see what happens.

{Edit} I said it compiles fine and runs, which it does, but with one warning. That warning points out that in your ReturnReference method, it doesn't return a value (object) on all return paths. For example, if the reference object type is not "Book", nothing is returned, which could cause the calling code to crash.
{/Edit}

Cheers!
Scorp
Quote:Original post by paintstripper88
I changed the line to ref.push_back(Reference("Book"));
Now I am getting the error:

New Reference Class has exited due to signal 11 (SIGSEGV).

Maybe what Scorp07, noticed, inserting a Reference at index 0 and accessing a nonexistent one at index 1?
Can't you fill the data before inserting into the vector? It would be simpler and more efficient.

Omae Wa Mou Shindeiru

0) The vector is a vector of References, so you can't push_back a std::string into it; you have to push_back a Reference into it. That means constructing a Reference first, and then putting it in. strtok's example does that by constructing an anonymous Reference; you don't need a variable of Reference type in order to make it work. This is the same as when you have a function "void foo(int)", and you call it with "foo(42);", instead of "int value = 42; foo(value);".

1) Clearly you didn't successfully work with an array of the class instances, because (a) your "working" commented-out code does nothing of the sort - it simply works with a single instance; and (b) the problem with the vector is one that you'd have with an array as well: array indices start at 0, not 1. This is done because it makes your life easier in the long run. Specifically, whenever you need to calculate an array index, you will find that the 0-based indexing leads to simpler math, with fewer strange +1's and -1's needed to make things line up right.

std::vector copies the array "interface" in this regard because (a) it is expected (by experienced programmers), (b) it was easier (for the implementor), and (c) it is easier (again, for experienced programmers to work with, for the same reasons it is with the array).

2) However, it makes more sense to construct the object fully before putting it in, instead of "reaching in" to the vector to set the other values.

3) Whatever book told you to write all those set and get functions - burn it. It is lying to you about what "encapsulation" means in C++, and making you do extra work - on both sides of the class - for something that actually isn't any better encapsulated at all. With the existing definition of the class, the only thing we should be hiding is the "ReferenceType" - because that value should never change or be inspected from outside after construction.

4) However, that's still awful design. Evidently, not all of the provided fields make sense for all the different "types" of references. In C++, we don't indicate sub-types by setting a field and checking it later; we indicate them by actually creating subtypes. Then, the parent Reference type only needs to contain those fields that are needed by all different sorts of References.

I didn't try to make the corresponding changes, though, because I don't know what kinds of References you need, and what data is appropriate for each.

5) In C++, we don't convert objects into strings for printing. Instead, we define how to feed them to output streams. Then, we can feed them directly (just like we do with ints or std::string instances) instead of calling the string-conversion function.

6) As noted, functions need to return something in all cases. The old ReturnReference() function had this problem: if the Reference *isn't* a book, what gets returned? The answer, according to C++ is, "I dunno, lol". The compiled code will blindly pick up whatever memory was in the chunk where it was expecting the return value to be, and pretend that garbage data represents a std::string object. All hell breaks loose after that. If you're lucky, the program will just crash right away. If not, you might get garbage output, or even something that seems to work fine, and then at some seemingingly random later time, your program crashes in a *completely different* place where the surrounding code is actually perfectly OK on its own. This is what we call "undefined behaviour".

You should be able to ask your compiler to warn you about this specific way of creating undefined behaviour. The specifics depend on which compiler it is.

7) Also in C++, we use initialization lists in constructors, as shown, and normally pass arguments of complex types (such as std::string) by const reference, as shown.

8) Oh, and don't waste time making fancy box comments. You'll regret it when you realize you need to change the comment for some reason, and waste more time keeping it "pretty". For that matter, don't waste time making a "the Foo class is here" type comment. You're not making it any easier to search for the Foo class in your code; just use 'class Foo' for your search text.

9) Don't compare strings to empty strings; use .empty() instead. It's clearer about what you mean ("is the string empty?").

10) And some other stuff, but it's easier to just show than explain...

#include <string>#include <vector>#include <iostream>using namespace std;class Reference {	string ReferenceType;	public:	string Author, Title, Journal, Year, Volume, Number, Pages, Note;	string Key, Booktitle, Editor, Organisation, Publisher, Address, Month;	string Series, Edition, Institution, Type, Howpublished;	Reference(const string& ReferenceType) : ReferenceType(ReferenceType) {}		friend ostream& operator<<(ostream&, const Reference&);}; ostream& operator<<(ostream& os, const Reference& r) {	if (r.ReferenceType == "Book") {		// Output each of the following in order, if they exist:		// author, year, title, edition/volume, address, publisher.		os << r.Author << " ";		if (!r.Year.empty()) { os << "(" << r.Year << ")."; }		os << " " << r.Title << " ";		bool haveEdition = !r.Edition.empty();		bool haveVolume = !r.Volume.empty();		if (haveEdition || haveVolume) {			// Pay close attention to the logic here ;)			os << "(";			if (haveEdition) { os << r.Edition << " ed."; }			if (haveEdition && haveVolume) { os << " "; }			if (haveVolume) { os << "Vol " << r.Volume << "."; }			os << ").";		}		os << " " << r.Address;		if (!r.Publisher.empty()) {			os << ":" << r.Publisher;		}	}	// We do this part even if it wasn't a Book:	return os;	// The result, if it's not a Book, is that nothing is printed, but the	// program carries on without any problems.}int main() {	vector<Reference> ref;	int i = 0; // Don't declare variables and then assign to them right	// away; instead, really *initialize* them. Also note the value ;)		Reference r("Book");	r.Author = "Daniel";	r.Title = "This is a title";	r.Year = "1999";		// Test it as is:	cout << r << endl;	// Test it within the vector:	ref.push_back(r);	cout << ref << endl; // see how easy :)}

This topic is closed to new replies.

Advertisement