Overloaded[] Operator with 2D Vector

I am trying to use a 2D string vector as a class private variable in unix with the bash subshell. It is a requirement that the overloaded operator[] be used in conjunction but I cannot get it working appropriately. My goal is to get an individual element from the vector and compare it to another string or print it to the screen. Here is the current function.

string &StringTable::operator[][](const int &sub, const int sub2)
{
return (stringV[sub][sub2]);
}

The programs error is that stringV is private. (My 2D string vector)
Any help would be appreciated.
If you declare the overloaded operator in your StringTable as a friend, that might deal with that problem (or not; I'm low on caffeine).

http://cplusplus.com/doc/tutorial/inheritance/

-Albatross
Last edited on
Ok, this here is my thing! :D

http://www.cplusplus.com/forum/general/26527/#msg141754

PS: Note to Disch:

mking wrote:
It is a requirement that the overloaded operator[] be used in conjunction
PS: Note to Disch:


lol.

It's still worth noting, of course, that [][] syntax shouldn't be preferred for this. If you absolutly have to do it for some reason (why?) then that's one thing, but if you're only using it because you're "used to it", then you really shouldn't be doing it.
I changed the coding to only use [] syntax, however in the main program I still want to use [][]. This is because a specific sequence of characters marks when a new row should be created and when a new portion of the vector starts. I use the [][] to find these characters. My new overload function is:

vector<string> &StringTable::operator[](int sub)
{
return (stringV[sub]);
}

I am still receiving the is private error. The overload is declared as a public function of StringTable and therefore should have the ability to access stringV right?
mking wrote:
I still want to use [][].

Mmmm... What Disch asks is what is the reason you want to use the [][] syntax instead of something like this:

1
2
3
4
string &StringTable::operator()(int sub, int sub2)
{
    return (stringV[sub][sub2]);
}

Could we see some more code?
Last edited on
Ok, here is example read in txt with # being the key char

Ain el Beida # - # - # OEB # Algeria # Africa # F # 42578 # 61997 # 90560 # #
Ain Oussera # - # - # EDJ # Algeria # Africa # F # 17173 # 44270 # 82435 # #
Ain Temouchent # - # - # ATE # Algeria # Africa # F # 38298 # 47479 # 54832 # #

Here is the StringTable class code and a stringUtil code that must also be used


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
////////////////////////////////////////
// StringTable.cpp

#include "StringTable.h"
#include<vector>
using namespace std;

////////////////////////////////////////

StringTable::StringTable(ifstream & infile)
{
	int i = 0;
	bool status = true;
	string hold;
	while (status)
	{
		status = readMultiWord(hold, infile);
		stringV[i].push_back(hold);
		if (stringV[i].back() == "#" && stringV[i][stringV[i].size() - 2] == "#")
			i++;
	}
}

int StringTable::rows() const
{
	return stringV.size();
}

vector<string> &StringTable::operator[](int sub)
{
	return (stringV[sub]);
}

////////////////////////////////////////
// stringUtil.cpp
// Matt King

#include "stringUtil.h"
using namespace std;

////////////////////////////////////////
// 'readMultiWord' reads a multiword string
//     terminated by 'sep' from 'infile' into 's';
// returns true if a multiword string read;
// returns false if the first word is a separator ('sep')
// Example: if 'infile' contains "Los Angeles # California"
//     then "Los Angeles" is stored in 's' and
//     position of 'infile' is now at "California"

bool readMultiWord(string & s, ifstream & infile, const string & sep)
{
	int pos = infile.tellg(); //holds current position so that the get pointer does not repoint to beginning each time

	infile.seekg(0, ios::end);
	int length = 0;
	length = infile.tellg();	//finds length of the infile for for loop
	infile.seekg(pos, ios::beg);

	string hold;
	hold = infile.get();	//holds the first char


	if (hold == sep)	//checking to make sure the first word is not a separator
	{
		s = sep;
		return 0;
	}
	else
	{
		s = infile.get();
		infile.seekg(1, ios::cur);
		hold = infile.get();
		for (int i = pos; i < length && hold != sep; i++)		//loop that runs until the end of file or sep is found
		{
			s.append(hold);
			infile.seekg(1, ios::cur);		//appends the next char onto the s string
			hold = infile.get();
		}
		s.append(hold);
		infile.seekg(1, ios::cur);	//gets off the sep char
	}

	return 1;
}

And finally the test file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
////////////////////////////////////////
// StringTableTester.cpp

#include <iostream>
#include <fstream>
#include "StringTable.h"
using namespace std;

int main(int argc, char *argv[])
{
	cout << "In Program";
	ifstream infile;
	infile.open("city-pop.txt");
	string hold;
	cout << "File Open, Table Not Made";
	StringTable cityTable(infile);
	int sepCounter = 0, counter4 = 0, counter5 = 0;
        
	cout << "variables";

	for (int i = 0; i < cityTable.rows(); i++)
	{
		if (cityTable.stringV[i].at(1) == "R" && cityTable.stringV[i].at(2) == "o" && cityTable.stringV[i].at(3) == "m" && cityTable.stringV[i].at(4) == "e")
		{
			hold = cityTable.stringV[i].at(1);
			for (int j = 0; j < cityTable.stringV.size(); j++)
			{
				if (cityTable.stringV[i][j] == "#")
					sepCounter++;
				if (sepCounter == 5)
					counter4 = j + 2;
				if (sepCounter == 6)
					counter5 = j + 2;
			}
    			sepCounter = 0;
			cout << cityTable.stringV[i].at(1) << cityTable.stringV[i].at(2) << cityTable.stringV[i].at(3) << cityTable.stringV[i].at(4) << "	";
			while (sepCounter < 2)
			{
				
				if (sepCounter == 0)
				{
					for (int m = counter4; m < counter5 - 3; m++)
					{
						cout << cityTable.stringV[i].at(m);
					}
					cout << "	";
				}
				else
					while (cityTable.stringV[i].at(counter5) != "#")
					{
						cout << cityTable.stringV[i].at(counter5);
						counter5++;
					}
				sepCounter++;
			}
		}
	}
    infile.close();
    // Return statement.
    return 0;
}
Last edited on
Regarding the [][] syntax, the thing is that you can't overload [][] because there is no such operator in C++. And you can't overload [] to take more than 1 parameters. But you can overload () to take two parameters. That would be a good solution here. But this doesn't seem to be the actual problem...

Is stringV a member of your StringTable class? If it's inherited from a super class and is private, your StringTable class can't access it. In that case you should make it a protected member. Could we see the header too?

EDIT: Where, exactly, does the error occur?
Last edited on
There is no mother class, stringV is a direct private member of the StringTable Class

Here are the two header files:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
////////////////////////////////////////
// stringUtil.h

#ifndef _STRING_UTIL_H
#define _STRING_UTIL_H

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

////////////////////////////////////////
// 'readMultiWord' reads a multiword string
//     terminated by 'sep' from 'infile' into 's'
// Example: if 'infile' contains "Los Angeles # California"
//     then "Los Angeles" is stored in 's' and
//     position of 'infile' is now at "California"

bool readMultiWord(string & s, ifstream & infile, const string & sep = "#");

#endif

////////////////////////////////////////
// StringTable.h

#ifndef _STRING_TABLE_H
#define _STRING_TABLE_H

#include <iostream>
#include <fstream>
#include <vector>
#include "stringUtil.h"
using namespace std;

////////////////////////////////////////

class StringTable
{
	public:
    ////////////////////////////////////////
    // 'StringTable' constructor
    // reads in a 2D table of multiword strings
    //     from file 'infile'
    // each multiword is separated by "#";
    // each row is separated by an extra "#";
    // yet another extra "#" at the end of rows 
    // Example (2 rows, 3 columns):
    // Los Angeles # California # USA # #
    // New York City # New York # USA # #
    // #

    		StringTable(ifstream & infile);

    ////////////////////////////////////////
    // 'rows' returns the number of rows

    		int rows() const;

    ////////////////////////////////////////
    // operator [] returns row at index 'i';
    // accessor (not a mutator);
    // returns a reference but not mutable;
    // TODO: write prototype, be careful about
    //     value vs. reference vs. constant reference

    		vector<string> &operator[](int);
	private:
    		vector<vector<string> > stringV;

   
};

#endif 



EDIT: The error that reoccurs at every instance where I use the operator is
StringTable.h:46: error: 'std::vector<std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::allocator<std::vector<std::basic_string<char,
std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >
StringTable::stringV' is private

and then it mentions that there is an error in the portion of the StringTableTester code where the operator is used.
Last edited on
Well, take a look at your main...

if (cityTable.stringV[i].at(1) == "R" && /*...*/

My guess is that you wanted to write:

if (cityTable[i].at(1) == "R" && /*...*/

You can't access cityTable.stringV directly inside main.

EDIT: Also, this -> for (int j = 0; j < cityTable.stringV.size(); j++)

should probably be -> for (int j = 0; j < cityTable.rows(); j++)

Last edited on
duh, let me try that =)
ok that problem is solved now it appears my final compiling program is that even as a string it will not let me compare an element of cityTable to #. It is a comparison of a signed int to an unsigned int. Thank you very much for all the help m4ster r0shi.

And rows returns the number of rows not the size but I came across that too and solved it.
Last edited on
mking wrote:
it will not let me compare an element of cityTable to #. It is a comparison of a signed int to an unsigned int.

I didn't quite get that... :/ Is this an error or a warning?
If it's a warning, then I think I know what it is; you may ignore it.

Also, notice that you can use cityTable[i][j] instead of cityTable[i].at(j);

Last edited on
It was a warning but when i run the file it seg faults, i put a cout at the beginning of each file but none display so its seg faulting before any file reaches code?
Sounds like a mentally unstable constructor.
L B wrote:
Sounds like a mentally unstable constructor.

Yeap.

@mking:

Try putting cout statements in your readMultiWord function and/or in your constructor.
Your file reading process could be a lot cleaner, you should work on it. These here could help:

http://www.cplusplus.com/reference/string/getline/
http://www.cplusplus.com/reference/string/operator%3E%3E/

(you can use the above with an ifstream object)

EDIT: Also, make sure there actually is a file named "city-pop.txt" and it is in the correct place.
Last edited on
Topic archived. No new replies allowed.