How to distinguish read/write operations when using operator[] - c++

I'd need to write a class with an overloaded operator [] which has different behavior when the operator [] is used to read or write data.
To give a practical example of what I want to achieve, let's say I have to write the implementation of a class named PhoneBook which can be used in the following way:
PhoneBook phoneBook(999999); // 999999 is the default number which should be
// used when calling someone who is not in the phone book
phoneBook["Paul"] = 234657; // adds Paul's number
phoneBook["John"] = 340156; // adds John's number
// next line should print Paul's number 234657
cout << "To call Paul dial " << phoneBook["Paul"] << endl;
// next line should print John's number 340156
cout << "To call John dial " << phoneBook["John"] << endl;
// next line should print 999999 because Frank is not in the phone book
cout << "To call Frank dial " << phoneBook["Frank"] << endl;
The problem is in the fact that when using
phoneBook["Frank"]
I don't want to add an entry in the phone book for Frank, otherwise a solution based on std::map would be easy to implement.
I did not find on the web any standard way to achieve this so
after some thinking I came up with the following solution in which the operator [] returns a "temporary object" named PhoneNumber. PhoneNumber is then used to distinguish between read/write operations:
#include <iostream>
#include <string>
#include <map>
using namespace std;
class PhoneBook{
private:
map<string, int> data_; // stores phone numbers
int defaultNumber_; // default number returned when no matching name is found
public:
PhoneBook(int defaultNumber) :
defaultNumber_(defaultNumber) {}
// Searches in the phone book for a name. If the name is found it returns
// the corresponding number. If the name is not found it returns defaultNumber_
int read(string name){
map<string, int>::iterator it = data_.find(name);
if (it==data_.end()){
return defaultNumber_;
} else {
return it->second;
}
}
// Forwarding function to map operator []. It is not really necessary but it is added for clarity
int& write(string name){
return data_[name];
}
// Forward declaration of the "temporary object" returned by operator []
// See declaration below
class PhoneNumber;
PhoneNumber operator[](string name){
return PhoneNumber(this, name);
}
class PhoneNumber{
friend class PhoneBook;
private:
PhoneBook* const phoneBook_;
string name_;
// Constructors are private so that PhoneNumber can be used only by PhoneBook
// Default constructor should not be used
PhoneNumber() :
phoneBook_(NULL) {}
PhoneNumber(PhoneBook* phoneBook, string name) :
phoneBook_(phoneBook), name_(name) {}
public:
// conversion to int for read operations
operator int (){
return phoneBook_->read(name_);
}
// assignment operator for write operations
const int& operator = (const int& val){
return phoneBook_->write(name_) = val;
}
};
};
int main(){
PhoneBook phoneBook(999999);
phoneBook["Paul"] = 234657;
phoneBook["John"] = 340156;
cout << "To call Paul dial " << phoneBook["Paul"] << endl;
cout << "To call John dial " << phoneBook["John"] << endl;
cout << "To call Frank dial " << phoneBook["Frank"] << endl;
return 0;
}
The class PhoneBook behaves like I would like and the program prints:
To call Paul dial 234657
To call John dial 340156
To call Frank dial 999999
I would like to ask you some questions:
Is there any better way to obtain a class behaving like the class I coded?
Has the technique I'm using a name so that I can search more info about it?
Do you see any drawback/possible improvement in my solution?
In the library I'm writing, enabling the behavior I obtained for PhoneBook::operator[]
in a similar situation is really important and I would really like to know what you think about my problem.
Thanks!

What you propose is the standard solution to this problem. It's usually
known as the proxy pattern or proxy idiom, and the helper class that you
return is called a proxy. (Since it is a nested class, simply calling
it Proxy is generally sufficient.)

I think you may implement two versions of operator [], one with const modifier and the other without. Then if you has a object say PhoneBook phoneBook(999999);, the if phoneBook is const object, only operator [] const can be called. If phoneBook is non-const object, default operator [] is called. If you want to call operator [] const given a non-const object, you may add a cast like static_cast<const PhoneBook&>(phoneBook)->operator[...].
#include <iostream>
#include <string>
#include <map>
using namespace std;
class PhoneBook{
private:
map<string, int> data_; // stores phone numbers
int defaultNumber_; // default number returned when no matching name is found
public:
PhoneBook(int defaultNumber) :
defaultNumber_(defaultNumber) {}
int operator [] (const string& name) const
{
map<string, int>::const_iterator it = data_.find(name);
if (it == data_.end())
{
return defaultNumber_;
}
else
{
return it->second;
}
}
int& operator [] (const string& name)
{
return data_[name];
}
};
int main(){
PhoneBook phoneBook(999999);
phoneBook["Paul"] = 234657;
phoneBook["John"] = 340156;
cout << "To call Paul dial " << phoneBook["Paul"] << endl;
cout << "To call John dial " << phoneBook["John"] << endl;
cout << "To call Frank dial " << static_cast<const PhoneBook&>(phoneBook)["Frank"] << endl;
return 0;
}

Related

Is there a way to always pass by value (Make a copy) rather than passing by reference when working with class member functions?

For a little background, I have been studying c++ for 3 months so I'm basically a newbie and I'm trying to understand classes that contain raw pointers as data members and how to use copy-contractors and move semantics with them.
So I have this simple class that contains a simple constructor/destructor and an unimplemented copy-constructor.
All I'm doing is creating an object using said class and then calling a member function with it.
So my question is:
Can I somehow always guaranty that when I call a member function I will make a copy of the object calling it and not pass it by reference?
You can easily pass something by reference if you add the "&" operator but what about passing something by value?
I have read that pass by value is the default way the compiler does it but for some reason when I execute my code the copy constructor is not called.
using namespace std;
class dog {
public:
string* name;
int* age;
dog(string NameVal = { "Null" }, int AgeVal = { 10 }) {
name = new string{ NameVal };
age = new int{ AgeVal };
cout << "constructor for " << *name << endl;
}
~dog() {
cout << "destructor for " << *name << " " << age << endl;
}
dog(const dog &source) {
cout << "copy constructor for " << *name << endl;
}
void talk(string text) {
cout << text << *name << endl;
}
};
int main() {
dog test;
test.talk("Test_Text ");
return 0;
}
So I expected the copy constructor to get called for the test object but it looks like it gets passed by reference using the "this" pointer.
How could I change that and actually make a copy of the object when calling the function?
Thanks for any help.
Well, if you want to copy the object and then call a function on the new object then you will need to do it explicitly:
dog test{};
dog{test}.talk("copy talk");
Note that you will also need to actually implement the copy constructor for this to work, otherwise class fields will be left uninitialized:
dog(const dog &source)
: name{new string{*(source.name)}}
, age{new int{*(source.age)}}
{
cout << "copy constructor for " << *name << endl;
}
Is there a way to always pass by value (Make a copy) rather than passing by reference when working with class member functions?
use a static operation receiving the instance by value
class dog {
...
static void talk(dog inst, string text) {
cout << text << *(inst.name) << endl;
}
...
};
int main() {
dog test;
dog::talk(test, "Test_Text ");
// or even
test.talk(test, "Test_Text ");
}

Is it possible to create a C++ class that mimics the std::cout syntax by chaining overloaded insertion operators the same way that easylogging++ does?

The easylogging++ code defines a macro that makes it very simple to use:
LOG(logLevel) << "This mimics std::cout syntax. " << 1 << " + " << 1 << " = " << 2;
I want to make a wrapper class for easylogging++. I can easily create a function with two parameters to wrap the above line. However, is it possible to mimic this syntax in a wrapper class? For example:
Logger logger;
logger(logLevel) << "Line " << 1 << " of log text.";
I know I can easily overload the insertion operator, but that still leaves me with having to write another function to set the log level each time.
UPDATE:
Thanks to Starl1ght's answer I was able to get this working. I figured I would share in case anyone else has a similar need.
I created two overloads. One was for () and the other for <<.
Logger &operator()(logLevelT logLevel) {
mLogLevel = logLevel;
return *this;
}
template <typename T>
Logger &operator<<(T const &value) {
LOG(mLogLevel) << value;
return *this;
}
UPDATE 2:
I wanted to update this post again to give my reasoning and show my final solution.
My reasoning is that my project is a demonstration of abstraction. I'm trying to demonstrate that logging libraries (and many other things) can be abstracted away from the core functionality of your software. This also makes the software components modular. This way I can swap out the easylogging++ library without loosing the syntax because it is implemented in the module interface.
My last update didn't mention how I overcame the obstacle of insertion chaining, so I wanted to post an example to show how I did it. The following code is a simplified example of how to achieve std::cout like syntax for a class.
#include <iostream> // For cout
#include <string> // For strings
#include <sstream> // For ostringstream
enum logLevelT {
INFO_LEVEL,
WARNING_LEVEL,
ERROR_LEVEL,
FATAL_LEVEL
};
class Logger {
private:
std::string logName;
public:
Logger(std::string nameOfLog, std::string pathToLogFile) {
logName = nameOfLog;
//TODO Configure your logging library and instantiate
// an instance if applicable.
}
~Logger(){}
// LogInputStream is instantiated as a temporary object. It is used
// to build the log entry stream. It writes the completed stream
// in the destructor as the object goes out of scope automatically.
struct LogInputStream {
LogInputStream(logLevelT logLevel, std::string nameOfLog) {
currentLogLevel = logLevel;
currentLogName = nameOfLog;
}
// Copy Constructor
LogInputStream(LogInputStream &lis) {
currentLogLevel = lis.currentLogLevel;
currentLogName = lis.currentLogName;
logEntryStream.str(lis.logEntryStream.str());
}
// Destructor that writes the log entry stream to the log as the
// LogInputStream object goes out of scope.
~LogInputStream() {
std::cout << "Logger: " << currentLogName
<< " Level: " << currentLogLevel
<< " logEntryStream = " << logEntryStream.str()
<< std::endl;
//TODO Make a log call to your logging library. You have your log level
// and a completed log entry stream.
}
// Overloaded insertion operator that adds the given parameter
// to the log entry stream.
template <typename T>
LogInputStream &operator<<(T const &value) {
logEntryStream << value;
return *this;
}
std::string currentLogName;
logLevelT currentLogLevel;
std::ostringstream logEntryStream;
};
// Overloaded function call operator for providing the log level
Logger::LogInputStream operator()(logLevelT logLevel) {
LogInputStream logInputStream(logLevel, logName);
return logInputStream;
}
// Overloaded insertion operator that is used if the overloaded
// function call operator is not used.
template <typename T>
Logger::LogInputStream operator<<(T const &value) {
LogInputStream logInputStream(INFO_LEVEL, logName);
logInputStream << value;
return logInputStream;
}
};
int main(int argc, char *argv[]) {
Logger logger1 = Logger("Logger1", "/path/to/log.log");
Logger logger2 = Logger("Logger2", "/path/to/log.log");
logger1(INFO_LEVEL) << "This is the " << 1 << "st test";
logger2(ERROR_LEVEL) << "This is the " << 2 << "nd test";
logger2 << "This is the " << 3 << "rd test";
return 0;
}
I feel like I could have done a better job with the naming and the comments but I am pressed for time. I'm definitely open to any comments or critiques.
You must overload operator() so, it will set internal log level and return *this as type Logger&, so, overloaded operator<< will work on returned reference with necessary log-level set.
Something like this:
Logger& Logger::operator()(LogLevel level) {
// set internal log level
return *this;
}

Accessing first element in Priority Queue c++

I am working on program in which I am require to use a priority queue. From my understanding the priority queue sorts the queue automatically from largest to smallest elements. I have create a simple priority queue of objects(nodes) that have a name and id number. I am trying to access the first object in the queue so I figured I could just use the "front" member function. This works when I use the standard queue but when I use a priority queue I get the error
error: 'class std::priority_queue' has no member named 'front'
I tried using "top" as well but then I get the error
error: passing 'const value_type (aka const node)' as 'this' argument
of 'void::display()' discards qualifiers [-fpermissive]
here is my code:
#include <iostream>
#include <queue>
using namespace std;
struct node
{
node(char n, int i) { name = n; id = i; }
void display() { cout << "name: " << name << " id : " << id << endl; }
friend bool operator < (node a, node b) { return a.id < b.id; }
private:
char name;
int id;
};
int main()
{
queue<node> myqueue; // Actually want a priority_queue<node>
myqueue.push(node('a',5));
myqueue.push(node('b',9));
myqueue.push(node('c',7));
myqueue.front().display(); // Error when using the type I want, even if I call top() instead
}
I will point out again that if I use queue instead of priority queue the code works. How do I access the front of a priority queue?
Your error is that .display() is not a constant member-function.
It should be:
void display() const { std::cout << "name: " << name << " id : " << id << '\n';}
As an aside, only use std::endl if explicitly flushing might be neccessary, as it flushes all hope of good performance down the drain.
Also read: Why is "using namespace std" considered bad practice?
Firstly, std::priority_queue::front does not exist. We just can't invoke something doesn't exist.
Secondly, be const-correct. Declare your member functions const.
void display() const
{...}
This is because the return type of std::priority_queue::top is a const reference. Via a const reference (and const value), only const member functions can be used. Inside a const member function, the object cannot be modified, which is the meaning of being const.
std::priority_queue::front does not exist.
Use
std::priority_queue::top
And yes, function display() should be const as mentioned by fellow member :)
void display() const { std::cout << "name: " << name << " id : " << id << '\n';}

C++ Using stringstream after << as parameter

Is it possible to write a method that takes a stringstream and have it look something like this,
void method(string str)
void printStringStream( StringStream& ss)
{
method(ss.str());
}
And can be called like this
stringstream var;
printStringStream( var << "Text" << intVar << "More text"<<floatvar);
I looked up the << operator and it looks like it returns a ostream& object but I'm probably reading this wrong or just not implementing it right.
Really all I want is a clean way to concatenate stuff together as a string and pass it to a function. The cleanest thing I could find was a stringstream object but that still leaves much to be desired.
Notes:
I can't use much of c++11 answers because I'm running on Visual Studio 2010 (against my will, but still)
I have access to Boost so go nuts with that.
I wouldn't be against a custom method as long as it cleans up this mess.
Edit:
With #Mooing Duck's answer mixed with #PiotrNycz syntax I achieved my goal of written code like this,
try{
//code
}catch(exception e)
{
printStringStream( stringstream() << "An exception has occurred.\n"
<<" Error: " << e.message
<<"\n If this persists please contact "<< contactInfo
<<"\n Sorry for the inconvenience");
}
This is as clean and readable as I could have hoped for.
Hopefully this helps others clean up writing messages.
Ah, took me a minute. Since operator<< is a free function overloaded for all ostream types, it doesn't return a std::stringstream, it returns a std::ostream like you say.
void printStringStream(std::ostream& ss)
Now clearly, general ostreams don't have a .str() member, but they do have a magic way to copy one entire stream to another:
std::cout << ss.rdbuf();
Here's a link to the full code showing that it compiles and runs fine http://ideone.com/DgL5V
EDIT
If you really need a string in the function, I can think of a few solutions:
First, do the streaming seperately:
stringstream var;
var << "Text" << intVar << "More text"<<floatvar;
printStringStream(var);
Second: copy the stream to a string (possible performance issue)
void printStringStream( ostream& t)
{
std::stringstream ss;
ss << t.rdbuf();
method(ss.str());
}
Third: make the other function take a stream too
Make your wrapper over std::stringstream. In this new class you can define whatever operator << you need:
class SSB {
public:
operator std::stringstream& () { return ss; }
template <class T>
SSB& operator << (const T& v) { ss << v; return *this; }
template <class T>
SSB& operator << (const T* v) { ss << v; return *this; }
SSB& operator << (std::ostream& (*v)(std::ostream&)) { ss << v; return *this; }
// Be aware - I am not sure I cover all <<'s
private:
std::stringstream ss;
};
void print(std::stringstream& ss)
{
std::cout << ss.str() << std::endl;
}
int main() {
SSB ssb;
print (ssb << "Hello" << " world in " << 2012 << std::endl);
print (SSB() << "Hello" << " world in " << 2012 << std::endl);
}
For ease of writing objects that can be inserted into a stream, all these classes overload operator<< on ostream&. (Operator overloading can be used by subclasses, if no closer match exists.) These operator<< overloads all return ostream&.
What you can do is make the function take an ostream& and dynamic_cast<> it to stringstream&. If the wrong type is passed in, bad_cast is thrown.
void printStringStream(ostream& os) {
stringstream &ss = dynamic_cast<stringstream&>(os);
cout << ss.str();
}
Note: static_cast<> can be used, it will be faster, but not so bug proof in the case you passed something that is not a stringstream.
Since you know you've got a stringstream, just cast the return value:
stringstream var;
printStringStream(static_cast<stringstream&>(var << whatever));
Just to add to the mix: Personally, I would create a stream which calls whatever function I need to call upon destruction:
#include <sstream>
#include <iostream>
void someFunction(std::string const& value)
{
std::cout << "someFunction(" << value << ")\n";
}
void method(std::string const& value)
{
std::cout << "method(" << value << ")\n";
}
class FunctionStream
: private virtual std::stringbuf
, public std::ostream
{
public:
FunctionStream()
: std::ostream(this)
, d_function(&method)
{
}
FunctionStream(void (*function)(std::string const&))
: std::ostream(this)
, d_function(function)
{
}
~FunctionStream()
{
this->d_function(this->str());
}
private:
void (*d_function)(std::string const&);
};
int main(int ac, char* av[])
{
FunctionStream() << "Hello, world: " << ac;
FunctionStream(&someFunction) << "Goodbye, world: " << ac;
}
It is worth noting that the first object sent to the temporary has to be of a specific set of types, namely one of those, the class std::ostream knows about: Normally, the shift operator takes an std::ostream& as first argument but a temporary cannot be bound to this type. However, there are a number of member operators which, being a member, don't need to bind to a reference! If you want to use a user defined type first, you need to extract a reference temporary which can be done by using one of the member input operators.

Ostream& operator<< overloading code not working

#include <string>
#include <iostream>
template <typename T>
T max(T a, T b) {
return a > b ? a : b;
}
class Dummy {
private:
std::string name;
int age;
public:
Dummy(int an_age) {age = an_age;}
bool operator> (Dummy &a) {return age > a.age;}
std::string toString() const {return "The age is " + age;}
};
std::ostream& operator<<(std::ostream& out, const Dummy& d) {return out<< d.toString();}
int main()
{
std::cout << max(3, 7) << std::endl;
std::cout << max(3.0, 7.0) << std::endl;
std::cout << max<int>(3, 7.0) << std::endl;
std::cout << max("hello", "hi") << std::endl;
Dummy d1(10);
Dummy d2(20);
std::cout << max(&d1, &d2) << std::endl;
return 0;
}
I'm pretty new to C++ but not new to programming. I've written the code to play with template and operator overloading in C++.
It took quite a while to make it compile and partially work.
The ostream operator<< is not working properly, only to return the address of the object. I can't figure out the causes.
I managed to make it compile by blind trial and error, so I suspect the code might be broken to some extent. And I may not be aware of what'd be improved.
Your max(&d1,&d2) expression gives you the address, and that is printed out. Your operator overloading is fine.
I assume the line you're talking about is
std::cout << max(&d1, &d2) << std::endl;
The problem is you are passing Dummy * instead of Dummy. That makes max return Dummy *, and since your overloaded operator<< takes (essentially) Dummy, it isn't invoked. If you're trying to pass by reference, you don't need to do anything special on the caller side, just make the function take a reference and the compiler will figure it out.
Don't write your own max, use the standard one instead:
#include <algorithm>
void f() { int a = std::max(8, 4); }
The only difference is that the standard max uses operator < by default, just like everything else in the standard library.
Your toString function does something different from what you think it does. It instead returns the sub string of "The age is " starting at the character number age. For example if age is 3, toString will return " age is ". To convert the integer to string you have to use ostringstream:
std::string toString() const {
std::ostringstream s;
s << "The age is " << age;
return s.str();
}