Is there a way in c++ to pass to a method a variable where that variable could be one of several different variables (of same type) depending on where the method is called.
For example:
A method to check if a file exists with the correct name.
At one point in the program, I might want to check a users file exists, so the user enters their username into string variable username, and that is passed to CheckFile:
bool LotterySystem::CheckFile(const std::string &USERNAME)
{
//if file exists, return false, else return true
FILE *fin = fopen((USERNAME + ".txt").c_str(), "r");
if (fin)
{
fclose(fin);
return false;
}
return true;
}
At another point I might want to check a file with stock information exists, so the user enters the stock they wish to check into string variable stockType:
bool LotterySystem::CheckFile(const std::string &STOCKTYPE)
{
//if file exists, return false, else return true
FILE *fin = fopen((STOCKTYPE + ".txt").c_str(), "r");
if (fin)
{
fclose(fin);
return false;
}
return true;
}
Is there a way to pass a generic string variable with any name, to CheckFile, without having to have different CheckFile methods for every file name to be checked?
You don't need differnt CheckFile methods. In fact, having more than one would result in a multiple definition error, because you are defining two methods with the same signature.
Just call it with different arguments:
LotterySystem ls;
ls.CheckFile("MyNameIsFred");
ls.CheckFile("MyPreferredPreferredStockName");
It seems like you want to pass different values of type const std::string, which in C++ can be passed simply using a single function. You will have to change the value which you are calling the function, not create different instances of the bool LotterySystem::CheckFile method.
And also, no compiler would compile the two instances of the same function, with same parameters.
bool LotterySystem::CheckFile(const std::string &USERNAME)
{
//if file exists, return false, else return true
FILE *fin = fopen((USERNAME + ".txt").c_str(), "r");
if (fin)
{
fclose(fin);
return false;
}
return true;
}
Then call:
LotterySystem mySystem;
std::string sName = "John Doe", sStockName = "ZXY";
bool nameFileExists = mySystem.CheckFile(sName);
bool stockFileExists = mySystem.CheckFile(sStockName);
It seems like you want to alter the semantics of the function by changing the name in the signature. That's not how it works. As chris states in the comments, the function's semantics stay the same, no matter what string you pass - only the return value will change, depending on what functions used in CheckFile return. Giving the string a different name does not create another overload of CheckFile and will not, in any way, alter the semantics or code flow within the function.
What you want is a dedicated function per purpose. CheckFile should just do what the name suggests(well, sort of): check whether the txt file denoted by the string you pass exists.
Layered on CheckFile you might want to implement additional functionality for the purpose of checking different types of files. That being said, if you're dealing with text-files, you need to parse and validate the contents anyway to be sure you actually have a valid user file or a stock-info file. In essence, you want something like this:
bool IsUserFile(const std::string&); // validates text-file contents
bool processUserFile(const std::string& path) // path omitting the extension '.txt'
{
if(!(CheckFile(path) && IsUserFile(path)))
return false;
// open file process contents
// return true if successful, false otherwise
}
Similarly for stock-info files.
On another note, there is no need to make such a function a member function of LotterySystem and if you insist on making it a member function, consider making it a static member function - it doesn't depend on an instance of LotterySystem.
Also, if I understand your intentions correctly, you want to check if a file exists. So, your CheckFile function needs to return true if it can open the file. Currently, it does exactly the opposite. Leave a comment if I'm mistaken.
Please note: checking for the existence of a file only by seeing if your application can open it is a very restricted case. It might exist and fopen() might still not be able to open it, be it due to insufficient privileges or other conditions.
Related
Hi can someone help me with this function:
bool createfile (string path);
It is supposed to create a file but my problem is:
What exactly the true or false have to do with creating a file?! How can I use it?
The bool is the return type of the function createfile(). Without the definition it is impossible to tell for sure what exactly this value is supposed to be, but often it is used to return if the function was successful in doing what it is supposed to do, in this case, create a file.
What exactly the true or false have to do with creating a file?!
You might want to return true if the file was successfully created or false otherwise.
How can I use it?
This depends on the body of the function and the purpose that you want to use the function for.
Quick answer
To directly answer the "How can I use it" part of your question:
You call it this way:
string path = "/path/to/my/file.txt";
bool returnedValue = createfile(path);
As for "What exactly the true or false have to do with creating a file?!", like mentionned in the other answers, it might indicate the success or failure of the operation, but you might want to double-check that, because the actual value will depend on the implementation of bool createfile(string path)...
Comprehensive answer
It seems you need some help interpreting the syntax of bool createfile(string path);
What we need to clarify here is that in c++ (and many other languages), the first word used in the function declaration is the return type.
You could compare this to some arbitrary mathematical function of the following form: here
x = a + b
In this case, x is the result of the addition function.
Assuming all the elements above are numbers, we could translate this in c++, like so:
int a = 0;
int b = 5;
int x = a + b;
We could extract the example above in a function (to reuse the addition), like so:
int add(int a, int b)
{
return a + b;
}
and use it in the following way (with a main to put some execution context around it):
int main()
{
int x = add(0,5);
return 0;
}
Here are some other examples of functions:
// simple non-member function returning int
int f1()
{
return 42;
}
// function that returns a boolean
bool f2(std::string str)
{
return std::stoi(str) > 0;
}
You'll find more details here. It might seem like a lot to take in (the page is dense with information), but it is a true reference.
I want to make my code more efficient, specifically the reading of data from a text file. Here is a snapshot of what it looks like now:
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)));
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)));
... // and so on
Basically, the read_value function creates an ifstream object, opens the file, reads one line of data, and closes the file connection. This happens many times. What I want to do is to open the file once, read every line that is needed into the struct, and then close the file connection.
Here is the creating values struct function with parameters:
static values create_struct(std::string name, std::map<std::string, int> mapping) {
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)), file);
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)), file);
// more values here
return V;
}
The function that calls create_struct is shown below:
void initialize_data(string name) {
// read the appropriate data from file into a struct
value_container = Utility::create_struct(name, this->mapping);
}
I am thinking of instead defining the ifstream object in the function initialize_data. Given what is shown about my program, would that be the best location to create the file object, open the connection, read the values, then close the connection? Also, would I need to pass in the ifstream object into the create_values struct, and if so, by value, reference or pointer?
The short answer is to create your ifstream object first and pass it as reference to your parser. Remember to seek the stream back to the beginning before you leave your function, or when you start to read.
The RAII thing to do would be to create a wrapper object that automatically does this when it goes out of scope.
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::ifstream& mStream;
}
Then you create a wrapper instance when entering a method that will read the fstream.
void read_value(std::ifstream& input, ...){
ifStreamRef autoRewind(input);
}
Or, since the Ctor can do the conversion...
void read_value(ifStreamRef streamRef, ...) {
streamRef.mStream.getLine(...);
}
std::ifstream itself follows RAII, so it will close() the stream for you when your stream goes out of scope.
The long answer is that you should read up on dependency injection. Don't create dependencies inside of objects/functions that can be shared. There are lots of videos and documents on dependency injection and dependency inversion.
Basically, construct the objects that your objects depend on and pass them in as parameters.
The injection now relies on the interface of the objects that you pass in. So if you change your ifStreamRef class to act as an interface:
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::string getLine(){
// todo : mStream.getLine() + return "" on error;
}
bool eof() { return mStream.eof(); }
std::ifstream& mStream;
}
Then later on you can change the internal implementation that would take a reference to vector<string>& instead of ifstream...
class ifStreamRef{
ifStreamRef(std::vector<string>& _in) : mStream(_in), mCursor(0){}
~ifStreamRef(){}
std::string getLine(){
// todo : mStream[mCursor++] + return "" on error;
}
bool eof() { return mCursor >= mStream.size(); }
std::vector<string>& mStream;
size_t mCursor;
}
I have oversimplified a few things.
This is a follow up question from here: C++ - Developing own version of std::count_if?
I have the following function:
// vector for storing the file names that contains sound
std::vector<std::string> FilesContainingSound;
void ContainsSound(const std::unique_ptr<Signal>& s)
{
// Open the Wav file
Wav waveFile = Wav("Samples/" + s->filename_);
// Copy the signal that contains the sufficient energy
std::copy_if(waveFile.Signal().begin(), waveFile.Signal().end(),
FilesContainingSound.begin(), [] (const Signal& s) {
// If the energy bin > threshold then store the
// file name inside FilesContaining
}
}
But to me, I only need to capture the string "filename" inside of the lambda expression, because I'll only be working with this. I just need access to the waveFile.Signal() in order to do the analysis.
Anyone have any suggestions?
EDIT:
std::vector<std::string> FilesContainingSound;
std::copy_if(w.Signal().begin(), w.Signal().end(),
FilesContainingSound.begin(), [&] (const std::unique_ptr<Signal>& file) {
// If the energy bin > threshold then store the
// file name inside FilesContaining
});
You seem to be getting different levels of abstraction confused here. If you're going to work with file names, then you basically want something on this order:
std::vector<std::string> input_files;
std::vector<std::string> files_that_contain_sound;
bool file_contains_sound(std::string const &filename) {
Wav waveFile = Wav("Samples/" + filename);
return binned_energy_greater(waveFile, threshold);
}
std::copy_if(input_files.begin(), input_files.end(),
std::back_inserter(files_that_contain_sound),
file_contains_sound);
For the moment I've put the file_contains_sound in a separate function simply to make its type clear -- since you're dealing with file names, it must take a file name as a string, and return a bool indicating whether that file name is one of the group you want in your result set.
In reality, you almost never really want to implement that as an actual function though--you usually want it to be an object of some class that overloads operator() (and a lambda is an easy way to generate a class like that). The type involved must remain the same though: it still needs to take a file name (string) as a parameter, and return a bool to indicate whether that file name is one you want in your result set. Everything dealing with what's inside the file will happen inside of that function (or something it calls).
I was working on some c++ code like this:
//c++ code
class MovieInfo;
MovieInfo getMovieInfoByName(String movieName)
{
//search the movieInfoList with movieName
if(FOUND)
return movieInfo;
//TODO: **what should i return if the movieInfo can't be found in the list?**
}
The question is what should i return if the movieInfo can't be found in the list?
You have several options:
Define the MovieInfo class such that an "invalid" instance is possible (similarly to how a default-constructed std::thread doesn't represent an actual thread) and return such an instance.
Make it a precondition of getMovieInfoByName() that the name corresponds to a valid movie info, and simply return a random value if it doesn't (as "violating preconditions leads to undefined behaviour").
Throw an exception when the name is not found.
Return something like boost::optional<MovieInfo>.
Give getMovieInfoByName() an extra parameter of type MovieInfo which would be used as the return value in case no match for the name is found.
It all depends on your intended use of the function.
It depends on the context and preconditions that must be met. For example if you are not sure whether the list contains such a movie by the time you call it, then it would be reasonable to do:
bool getMovieInfoByName(const std::string& movieName, MovieInfo& movieInfo)
{
...
if (FOUND) {
movieInfo = ...;
return true;
}
return false;
}
since the caller will most likely have to know whether the movie with such a movie exists or not.
If it shouldn't happen that getMovieInfoByName will not find the movie, i.e. the caller should already know whether the list contains such a movie by other means, then it is perfectly reasonable to throw an exception since it is exceptional state and rather indicates the wrong usage of this method.
There's also a design pattern called Null Object, which is based on constructing an object, state of which can indicate whether it is a valid / initialized object or it is a dummy instance representing NULL.
In this case the caller would most likely still have to check whether appropriate MovieInfo instance has been returned and this class should provide a method such as bool isValid();.
I am trying to add few configurable properties to an existing code/project. I found it is really annoyance to have so many steps to do this:
add entry to the configuration file;
declare a key string in the h file;
define that key string in the cpp file;
declare a getXXX method/function in the h file;
define that getXXX method/function in the cpp file;
In our case, that header file and cpp file are only for properties read from text file and those properties are only needed inside this module. So we may be able to simplify them with less files or less steps. Any idea/suggestion?
EDIT:
A map is used to hold contents from the text file.
A sample get method likes this:
unsigned int Module1Config::getSleepTime()
{
return getPropertyMap().getUnsignedIntProperty(SLEEP_TIME_KEY);
}
What about a private std::map whose keys are just those declared in the configuration file. Then, you can have a getter function that gets the value typed as you need it, with a default value if it does not exist:
template<class T>
T get(const std::string &key) const
{
if the key is in the map,
return its value converted to type T
else
return T();
}
You may find useful a second function to tells you if some key is declared:
bool exists(const std::string &key) const
{
return true iif key is in the map
}
The pros of this approach is that you don't need to modify the class when new properties are added. The con is that key names are not created as constant identifiers in your h file, so you have to use strings all the time, which may be error prone. Anyway, I think its versatility is worth it (this is the method I use in my programs).