I have several types that share common behaviour and with same constructors and operators. Some look like this:
class NumberOfFingers
{
public:
void operator=(int t) { this->value = t; }
operator int() const { return this->value; }
private:
int value;
};
NumberOfToes is identical.
Each class has different behaviour, here is an example:
std::ostream& operator<<(std::ostream &s, const NumberOfFingers &fingers)
{
s << fingers << " fingers\n";
}
std::ostream& operator<<(std::ostream &s, const NumberOfFingers &toes)
{
s << toes << " toes\n";
}
How can I minimise the duplication in the class definitions, whilst keeping class types distinct? I don't want to have NumberOfFingers and NumberOfToes derive from a common base class because I lose the constructor and operators. I would guess a good answer would involve templates.
Yes, you are correct in that it would involve templates :)
enum {FINGERS, TOES...};
...
template<unsigned Type> //maybe template<enum Type> but I havent compiled this.
class NumberOfType
{
public:
void operator=(int t) { this->value = t; }
operator int() const { return this->value; }
private:
int value;
};
...
typedef NumberOfType<FINGERS> NumberOfFinger
typedef NumberOfType<TOES> NumberOfToes
... so on and so forth.
Related
I have two wrapper classes for string and int and one to represent Binary Operation and overloading the operator << to write them in a string format. Unfortunately, I can't overload << without friend function and I can't get polymorphism without virtual and can't use friend with virtual !!
#include <iostream>
#include <string>
class AST {};
class expr: public AST {};
class operator_: public AST {};
class BinOp: public expr {
private:
expr *_left;
expr *_right;
operator_ *_op;
public:
BinOp(expr *p_left, expr *p_right, operator_ *p_op):_left(p_left),_right(p_right),_op(p_op) {}
friend std::ostream &operator<< (std::ostream &out, const BinOp &binop) {
out << (binop._left) << " " << (binop._op) << " " << (binop._right);
}
};
class LShift: public operator_ {
public:
LShift() {}
friend std::ostream &operator<< (std::ostream &out, const LShift &lshift) {
out << "<<";
}
};
class Name: public expr {
private:
std::string _id;
public:
Name(std::string p_id) { _id = p_id; }
friend std::ostream &operator<< (std::ostream &out, const Name &name) {
out << name._id;
}
};
class Num: public expr {
private:
int n;
public:
Num(int p_n) { n = p_n; }
friend std::ostream &operator<< (std::ostream &out, const Num &num) {
out << num.n;
}
};
int main() {
auto name = Name("x");
auto num = Num(5);
auto lshift = LShift();
auto binop = BinOp(&name, &num, &lshift);
std::cout << binop << '\n';
return 0;
}
So the program mentioned above outputs the pointer,
0x7ffd05935db0 0x7ffd05935d8b 0x7ffd05935d8c
but instead of a pointer, I need the objects needed to print.
x << 5
In general, having operator overloading an polymorphism in the same class is an indication that you're mixing value-style classes and identity-style classes, and thus a C++-specific code smell.
But I would say that the stream insertion operator is an exception.
The solution is to overload the operator once, and forward to a function that is more amenable to overriding.
class AST {
public:
virtual void print(std::ostream& s) const = 0;
virtual ~AST() {} // you probably want this one too
};
// no need for friendliness
std::ostream& operator <<(std::ostream& s, const AST& node) {
node.print(s);
return s;
}
And then you put the actual printing logic into the print overrides of each class.
But I also feel the need to remark that your AST class doesn't seem useful. There is really nothing an operator and a binary expression have in common. It's also conceptually wrong to say that an operator or an expression is an abstract syntax tree. An expression is a part of an AST, a single node in the tree. An operator is a part of an expression. The entire tree is something different.
You should have separate hierarchy roots for operator_ and expr. And yes, that probably means you have to do the printing stuff twice. It's worth it.
I am learning C++, and learned that int-types are just premade classes. So I thought maybe i should try to create one.
What I want to do basically is a
normal class of int
int x;
x=7;
cout << x;
// Output is 7 on screen.
so similarly...
abc x;
x=7;
cout << x;
What would I put in
class abc{
\\ HERE!!!!!!
};
so I could do this
class SomeClass {
public:
int x;
SomeClass(int x) {
this->x = x;
}
};
int main(int argc, char *argv[]) {
SomeClass s = 5;
cout << s.x << "\n"; // 5
s = 17;
cout << s.x << "\n"; // 17
return 0;
}
But as you can see I have to use s.x to print the value - I just want to use 's'.
I am doing it as an experiment, I don't want to hear about how this method is good or bad, pointless or revolutionary, or can 't be done. I remember once I did it. But only by copying and pasting code that I didn't fully understand, and have even forgotten about.
and learned that int, types, are just premade classes
This is completely false. Still, you have complete control on how your class will behave in expressions, since you can overload (almost) any operator. What you are missing here is the usual operator<< overload that is invoked when you do:
cout<<s;
You can create it like this:
std::ostream & operator<<(std::ostream & os, const SomeClass & Right)
{
Os<<Right.x;
return Os;
}
For more information, see the FAQ about operator overloading.
the << and >> are basically function names. you need to define them for your class. same with the +, -, * and all the other operators. here is how:
http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html
You need to overload operator<< for your class, like so:
class abc
{
public:
abc(int x) : m_X(x) {}
private:
int m_X;
friend std::ostream& operator<<(std::ostream& stream, const abc& obj);
};
std::ostream& operator<<(std::ostream& os, const abc& obj)
{
return os << obj.m_X;
}
You don't have to friend your operator<< overload unless you want to access protected/private members.
You must define in your class abc cast operator to int and assignment operator from int, like in this template class:
template <class T>
class TypeWrapper {
public:
TypeWrapper(const T& value) : value(value) {}
TypeWrapper() {}
operator T() const { return value; }
TypeWrapper& operator (const T& value) { this->value = value; return *this; }
private:
T value;
};
int main() {
TypeWrapper<int> x;
x = 7;
cout << x << endl;
}
You want to overload the output operator:
std::ostream& operator<< (std::ostream& out, SomeClass const& value) {
// format value appropriately
return out;
}
Is nesting overloaded operators possible ? I would like to nest << inside a ()
template<class T>
struct UnknownName
{
T g;
T&operator<<(std::ostream&os, const T&v){return os<<v;}
bool operator()(const T&v)
{
if(v==g)
//do the streaming << then return true
else return false;
}
};
Would you please help me out ? I am afraid my example is unreal enough to you, please just ask if you still have any doubts. Sincerely.
I can't really tell what you're asking, but I assume you mean write a class to the ostream& that gets passed to operator<<. First you have to make up a way to convert a T to a string representation. I'll assume the function TToString does that.
template<class T>
struct UnknownName
{
T g;
bool operator()(const T&v)
{
if(v==g) {
cout << v;
return true;
}
return false;
}
friend std::ostream& operator<<(std::ostream& os, const T& v) {
return os << TToString(v);
}
};
Sorry if I misinterpreted your question.
The best I can think of would be to have operator<< return a specific type, and then overload operator() to accept that type:
#include <cstdio>
namespace {
struct Foo {
struct Bar {
int i;
};
Foo& operator()(const Bar& b)
{
std::printf("bar, %d\n", b.i);
return *this;
}
// obviously you don't *have* to overload operator()
// to accept multiple types; I only did so to show that it's possible
Foo& operator()(const Foo& f)
{
std::printf("foo\n");
return *this;
}
};
Foo::Bar operator<<(const Foo& f, const Foo& g)
{
Foo::Bar b = { 5 };
return b;
}
}
int main()
{
Foo f, g, h;
f(g << h);
f(g);
}
This isn't a common idiom, to say the least.
The following won't compile for me. I'm out of ideas... Any help?
template<>
inline
std::ostream& operator<< <const std::map<std::string, std::string> > (std::ostream& stream, const std::map<std::string, std::string>& some_map)
{
return stream;
}
g++ gives me the following error:
error: expected initializer before '<' token
Edit: 1
Okay, since everyone is telling me to overload, let me give you an example that wouldn't make sense for overloading. What if I have this:
template <typename T>
inline
std::ostream& operator<<(std::ostream& stream, const T& something)
{
stream << something.toString();
return stream;
}
class Foo
{
public:
Foo(std::string s)
{
name = s;
}
std::string toString() const
{
return name;
}
private:
std::string name;
};
class Bar
{
public:
Bar(int i)
{
val = i;
}
std::string toString() const
{
std::ostringstream stream;
stream << val;
return stream.str();
}
private:
int val;
};
int main(int, char**)
{
Foo foo("hey");
Bar bar(2);
std::cout << foo << std::endl;
std::cout << bar << std::endl;
return 0;
}
Now this won't work either.
I just want to avoid having to overload operator<< over and over by using a template like above. This seems like it should be possible. I would like to know if it is, and if so, how?
In such a scenario, overloading for both Foo and Bar to do the same thing would be a waste, that is why I am trying to avoid it.
Edit: 2
Okay, it appears that I am being misunderstood. Here is another attempt to clarify:
template <typename T>
std::ostream& operator<<(ostream& stream, const T& t)
{
for(typename T::const_iterator i = t.begin(), end = t.end(); i != end; ++i)
{
stream << *i;
}
return stream;
}
int main(int, char**)
{
set<int> foo;
list<string> bar;
vector<double> baz;
cout << foo << " " bar << " " << baz << endl;
};
The above code won't work mind you. Complains about ambiguity. But it seems like the better solution for printing out containers. If I did it the with overloading, I would need to write a version of operator<< for each container/datatype combination, which would yield a ridiculous amount of code duplication.
This doesn't need to be a template function.
std::ostream & operator<<(std::ostream & stream, const std::map<std::string, std::string> & some_map)
{
return stream;
}
Edit:
In reference to my comment about writing Java in C++(and sorry if it sounded rude, I didn't intend to be smarmy). Tell me if this doesn't work better for you. Instead of writing a "toString" method in the first place, just overload the operator<< to begin with. The function is nearly identical. Then, you can write a non-member template toString function that will automatically work with all of your classes, like this:
#include <sstream>
#include <string>
template<typename T>
std::string toString(const T & val)
{
std::ostringstream ostr;
ostr << val;
return ostr.str();
}
Edit 2
Here's my alternative if you still insist on doing it your way. Make all of your classes with the toString method inherit from an abstract class with a virtual toString method, then write one operator<< to handle all of them.
class Stringifiable
{
public:
virtual std::string toString() const = 0;
};
std::ostream & operator<<(std::ostream & ostr, const Stringifiable& something)
{
return ostr << something.toString();
}
Now the compiler will choose your overload over templates.
You can use SFINAE to remove the template overload from consideration. Note that this has to be a part of the signature of the function. Thus you can use boost::enable_if:
template < typename T >
typename boost::enable_if< meta_function_to_check_for_concept<T>, std::ostream&>::type
operator << (std::ostream & out, T const& t)
{
...
}
If you don't do this then your template will attempt to match almost anything and will explode for every use of << that is not in line with the concept you're trying to match.
Your example is a bit contrived and might not lend itself to this answer, but there are situations in which it's warranted. This is how to do it.
In Crazy Eddie's answer, he mentions SFINAE. Now, C++11 has that built in. If all types derive from the same base class, this is made pretty simple. Here's a more complete example using C++11:
#include <type_traits>
#include <iostream>
#include <ostream>
class MyBaseType {};
class MyClass : MyBaseType {};
class MyOtherClass : MyBaseType {};
class SomeType {};
template <typename T>
typename std::enable_if<std::is_base_of<MyBaseType,T>::value,std::ostream&>::type
operator<<(std::ostream& out, const T& x)
{
out << 1;
}
int main()
{
MyBaseType x;
MyClass y;
MyOtherClass z;
SomeType i;
std::cout << x << y << z; // success!
std::cout << i; // compile-time failure!
}
Just as the title asks, does C++ have the equivalent of Python's setitem and getitem for classes?
Basically it allows you to do something like the following.
MyClass anObject;
anObject[0] = 1;
anObject[1] = "foo";
basically, you overload the subscript operator (operator[]), and it returns a reference (so it can be read as well as written to)
You can overload the [] operator, but it's not quite the same as a separate getitem/setitem method pair, in that you don't get to specify different handling for getting and setting.
But you can get close by returning a temporary object that overrides the assignment operator.
To expand on Earwicker post:
#include <string>
#include <iostream>
template <typename Type>
class Vector
{
public:
template <typename Element>
class ReferenceWrapper
{
public:
explicit ReferenceWrapper(Element& elem)
: elem_(elem)
{
}
// Similar to Python's __getitem__.
operator const Type&() const
{
return elem_;
}
// Similar to Python's __setitem__.
ReferenceWrapper& operator=(const Type& rhs)
{
elem_ = rhs;
return *this;
}
// Helper when Type is defined in another namespace.
friend std::ostream& operator<<(std::ostream& os, const ReferenceWrapper& rhs)
{
return os << rhs.operator const Type&();
}
private:
Element& elem_;
};
explicit Vector(size_t sz)
: vec_(sz)
{
}
ReferenceWrapper<const Type> operator[](size_t ix) const
{
return ReferenceWrapper<const Type>(vec_[ix]);
}
ReferenceWrapper<Type> operator[](size_t ix)
{
return ReferenceWrapper<Type>(vec_[ix]);
}
private:
std::vector<Type> vec_;
};
int main()
{
Vector<std::string> v(10);
std::cout << v[5] << "\n";
v[5] = "42";
std::cout << v[5] << "\n";
}
It's not portable, but MSVC has __declspec(property), which also allows indexers:
struct Foo
{
void SetFoo(int index, int value) { ... }
int GetFoo(int index) { ... }
__declspec(property(propget=GetFoo, propput=SetFoo)) int Foo[];
}
other than that, Earwicker did outline the portable solution, but he's right that you'll run into many problems.