Hello,

I'm currently working on a project that basically reads some text and then performs basic Lexical Analysis on the text. I'm having a slight problem
with overloading methods.

So for example, I have a method that can read in the words from a txt file and another method which reads takes the text just from a string, but, I'm using the same method name, and, the same variable type so obviously it cannot be overloaded. For example:

#ifndef _readWords_h
#define _readWords_h

#include <iostream>
#include <vector>
using namespace std;

class Lexical
{
    public:

        Lexical();
        Lexical(string theFileName);

        vector<string> Parser(string fileName);
        vector<string> Parser(string theWords);

    protected:
        vector<string> words;
        string fileName; 

};

#endif

The method Parser cannot be overloaded. Now is there a way that I could overload this method OR should I have two more classes that inherit from this class and have Parser as a virtual function and call the correct class? E.g. readFromTXT, readFromString both inheriting from Lexical.

Any help would be greatly appriciated :)

Recommended Answers

All 5 Replies

Why not have the file version take an istream object? Something like:

vector< string > Parser (std::istream& in);

That way it is clear the intent of the function and you can still use the string version without issue.

That depends, I would say, on how you mean to use the two methods. Personally, I would probably have only one form of the method, one which takes an istream& as it's argument; this covers both the case of a file input (ifstream&) and string input (istringstream&), and gives you additional options besides (e.g., reading from std::cin for a filter).

I would add that you may want to have it return a vector of an abstract Token class, rather than of plain std::strings. This would allow you to specialize the set of tokens a given Lexical object returns with additional information aside from the contents of the string itself.

Or perhaps you could combine the two sets of ideas, and have it return a stream of Tokens? You'd need to define a tokenstream class, as an extended form of an ios, and then... hmmn, let me think this out a bit.

First of all, if the idea of the Parser function is to fill the vector of words contained in Lexical, then I see no point in returning that vector of words from the function.

As for the overloading problem, I would recommend just going with the std::istream idea. The standard way to extract any kind of non-trivial information from a std::string is to put it in a std::stringstream anyways (which is convertible to std::istream&, so you might as well have the user of your Lexical class do so at the call site. And, while you are dealing with the std::istream class, you might as well use the >> operator instead of a function call. So, for a simple "extract space-separated words" Lexical analyzer, you could do this:

class Lexical
{
    public:
        Lexical();

        friend
        istream& operator >>(istream& in, Lexical& lex);

        friend
        ostream& operator <<(ostream& out, const Lexical& lex);

    protected:
        vector<string> words;
};

istream& operator >>(istream& in, Lexical& lex) {
    string s;
    getline(in, s, '\n');
    stringstream ss(s);
    while( ss >> s )
        lex.words.push_back(s);
    return in;
};

ostream& operator <<(ostream& out, const Lexical& lex) {
    for(unsigned int i = 0; i < lex.words.size(); ++i)
        out << lex.words[i] << " ";
    return out;
};

int main() {
    ifstream file_in("my_file.txt");
    Lexical lex1;
    file_in >> lex1;    // input the words into the Lexical object.
    cout << "File words are: " << lex1 << endl;  // output the words.

    Lexical lex2;
    cout << "Please enter a sentence: ";
    cin >> lex2;      // input the words from cin.
    cout << "Inputted words are: " << lex2 << endl;  // output the words.

    Lexical lex3;
    string sentence = "This is a sentence.";
    stringstream ss(sentence);
    ss >> lex3;       // input the words from a stringstream.
    cout << "Sentence words are: " << lex3 << endl;   // output the words.

    return 0;
};

As you see, the use of your lexical class becomes very natural when using the operators that are natural to C++ programmers. And the above versatile (all input methods are handled uniformly) and scalable (any input method can be used, as long as it derives from std::istream), and allows you to code only the part of the lexical analysis that you need to implement (i.e., take the words from a stream and analyse them) without the code-pollution coming from the different input methods that you might want to support. The job of the std::istream is to handle the details of the input method (file, string, console, network, etc.) and the job of the Lexical class is to analyse the words (or sentence) that it is given, by clearly splitting those responsabilities, you get really neat code.

Another option is to make a File struct.

struct FileInfo{
    std::string name;
    //possibly other things
    explicit FileInfo(const std::string& name = ""): name(name){}
}

class Lexical{
     ReturnType read(const std::string& sentence);
     ReturnType read(const FileInfo& fileInfo);
}

but I suggest to go the istream route as suggested in previous post.

Hey - Thank you so much for your help. I've only just seen this again but it's solved now =)

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.