I posted a question earlier about how to overload strings, But when I use the same formula for unsigned long long it doesn't work.
I tried a typedef but that didn't work either.
typedef unsigned long long i64;
//a new class to hold extention types, and bytes.
class FileData
{
public:
//conversion operators
operator string(){return extensions_;}
operator i64() {return containsBytes_;}
string& operator= (FileData &);
i64& operator= (FileData &);
string extensions_;
i64 containsBytes_;
};
string &FileData::operator=(FileData& fd)
{
return fd.extensions_;
}
i64 &FileData::operator=(FileData& fd)
{
return fd.containsBytes_;
}
there are two errors in this code.
first one is on line 11:
Error:cannot overload functions distinguished by return types alone
second one is on line 22,
Error:declaration is incompatible with "std::string &FileData::operator=(FileData& fd)"(declared on line 17).
but if I delete any mention of the string conversion it still doesn't work.
I think what you are looking for is these
FileData& operator= (string&);
FileData& operator= (i64&);
FileData& FileData::operator=(string& s)
{
this->extensions_ = s;
return *this;
}
FileData& FileData::operator=(i64& l)
{
this->containsBytes_ = l;
return *this;
}
You are confusing assignment with type conversion operators. Assignment operator is used when you want to assign something to your class. Not to make it compatible with string or long long
With assignment for string overloaded you can do this
FileData a;
string str;
a = str; // This will set a.extensions_ to str, see above.
but not.
str = a;
Because assignment expects your class on the left hand side.
To do str = a; you need to overload conversion operators (). Which you have done.
operator string(){return extensions_;}
With those overloaded
str = a; // This will set str to a.extensions_ See the difference?
First error message
Error:cannot overload functions distinguished by return types alone
These two functions have identical parameters and differ only in return types
string& operator= (FileData &);
i64& operator= (FileData &);
C++ can overload functions only, when they differ in parameters.
Second error message
Error:declaration is incompatible with "std::string &FileData::operator=(FileData& fd)"(declared on line 17).
i64 &FileData::operator=(FileData& fd)
{
return fd.containsBytes_;
}
This is a follow up to the first error. The C++ compiler ignored the second assignment operator, because there was no differing parameters. Now, you define an assignment operator, which is incompatible with the assignment operator declared first above.
Related
I am trying to override operator+ and operator= for my classes.
This is my code:
#include <iostream>
#include <vector>
using namespace std;
class Integer {
public:
int i;
Integer operator+ (Integer&);
Integer& operator= (Integer&);
};
Integer Integer::operator+(Integer& rhs) {
Integer res;
res.i = this->i + rhs.i;
return res;
}
Integer& Integer::operator=(Integer& rhs) {
this->i = rhs.i;
return *this;
}
int main()
{
Integer i1, i2, i3;
i1.i = 1, i2.i = 2;
i3 = i1 + i2;
cout << i3.i;
}
In visual studio 2017, the compiler complained that:
"E0349 no operator "=" matches these operands"
It seems that an Integer object doesn't match with Integer& in the operator= function. But it works for operator+ function. It is very confusing.
Thanks a lot.
i3 = i1 + i2;
returns a temporary variable of type Integer.
Now, your operator= takes a Integer&. This is a reference to an Integer. The problem is that temporaries cannot bind to non-const references.
Just make sure you change to const Integer&. That is the default for all operator overloads anyway.
I'll break this down from the assignment statement.
i3 = i1 + i2;
The first thing that happens were is the addition expression gets evaluated.
That's this code snippet:
i1 + i2
You designed your operator overload to handle this expression.
Your custom addition operator overload returns a new Integer instance.
But the problem occurs when you try to assign this new instance to the parameter
in your assignment overload. Here's a snippet of that code.
Integer& Integer::operator=(Integer& rhs);
When you use a referenced parameter in a function declaration, the compiler checks to make sure that this value is not a temporary value, so that it will exist after the function is called. The compiler has determined (correctly) that the argument passed to this assignment statement is a temporary value. That is why it spits out an error when you try to do this.
The most logical why I see of making your code make sense is to implement the following:
Integer& Integer::operator=(const Integer& rhs) {
this->i = rhs.i;
return *this;
}
By adding the const-specifier, you tell the compiler that you're not relying on rhs to persist existence after calling the function. In that case, the value passed to the parameter may be a temporary value.
I was trying to understand the usage of explicit keyword in c++ and looked at this question on SO
What does the explicit keyword mean in C++?
However, examples listed there (actually both top two answers) are not very clear regarding the usage. For example,
// classes example
#include <iostream>
using namespace std;
class String {
public:
explicit String(int n); // allocate n bytes to the String object
String(const char *p); // initializes object with char *p
};
String::String(int n)
{
cout<<"Entered int section";
}
String::String(const char *p)
{
cout<<"Entered char section";
}
int main () {
String mystring('x');
return 0;
}
Now I have declared String constructor as explicit, but lets say if I dont list it as explicit, if I call the constructor as,
String mystring('x');
OR
String mystring = 'x';
In both cases, I will enter the int section. Until and unless I specify the type of value, it defaults to int. Even if i get more specific with arguments, like declare one as int, other as double, and not use explicit with constructor name and call it this way
String mystring(2.5);
Or this way
String mystring = 2.5;
It will always default to the constructor with double as argument. So, I am having hard time understanding the real usage of explicit. Can you provide me an example where not using explicit will be a real failure?
explicit is intended to prevent implicit conversions. Anytime you use something like String(foo);, that's an explicit conversion, so using explicit won't change whether it succeeds or fails.
Therefore, let's look at a scenario that does involve implicit conversion. Let's start with your String class:
class String {
public:
explicit String(int n); // allocate n bytes to the String object
String(const char *p); // initializes object with char *p
};
Then let's define a function that receives a parameter of type String (could also be String const &, but String will do for the moment):
int f(String);
Your constructors allow implicit conversion from char const *, but only explicit conversion from int. This means if I call:
f("this is a string");
...the compiler will generate the code to construct a String object from the string literal, and then call f with that String object.
If, however, you attempt to call:
f(2);
It will fail, because the String constructor that takes an int parameter has been marked explicit. That means if I want to convert an int to a String, I have to do it explicitly:
f(String(2));
If the String(char const *); constructor were also marked explicit, then you wouldn't be able to call f("this is a string") either--you'd have to use f(String("this is a string"));
Note, however, that explicit only controls implicit conversion from some type foo to the type you defined. It has no effect on implicit conversion from some other type to the type your explicit constructor takes. So, your explicit constructor that takes type int will still take a floating point parameter:
f(String(1.2))
...because that involves an implicit conversion from double to int followed by an explicit conversion from int to String. If you want to prohibit a conversion from double to String, you'd do it by (for example) providing an overloaded constructor that takes a double, but then throws:
String(double) { throw("Conversion from double not allowed"); }
Now the implicit conversion from double to int won't happen--the double will be passed directly to your ctor without conversion.
As to what using explicit accomplishes: the primary point of using explicit is to prevent code from compiling that would otherwise compile. When combined with overloading, implicit conversions can lead to some rather strange selections at times.
It's easier to demonstrate a problem with conversion operators rather than constructors (because you can do it with only one class). For example, let's consider a tiny string class fairly similar to a lot that were written before people understood as much about how problematic implicit conversions can be:
class Foo {
std::string data;
public:
Foo(char const *s) : data(s) { }
Foo operator+(Foo const &other) { return (data + other.data).c_str(); }
operator char const *() { return data.c_str(); }
};
(I've cheated by using std::string to store the data, but the same would be true if I did like they did and stored a char *, and used new to allocate the memory).
Now, this makes things like this work fine:
Foo a("a");
Foo b("b");
std::cout << a + b;
...and, (of course) the result is that it prints out ab. But what happens if the user makes a minor mistake and types - where they intended to type +?
That's where things get ugly--the code still compiles and "works" (for some definition of the word), but prints out nonsense. In a quick test on my machine, I got -24, but don't count on duplicating that particular result.
The problem here stems from allowing implicit conversion from String to char *. When we try to subtract the two String objects, the compiler tries to figure out what we meant. Since it can't subtract them directly, it looks at whether it can convert them to some type that supports subtraction--and sure enough, char const * supports subtraction, so it converts both our String objects to char const *, then subtracts the two pointers.
If we mark that conversion as explicit instead:
explicit operator char const *() { return data.c_str(); }
...the code that tries to subtract two String objects simply won't compile.
The same basic idea can/does apply to explicit constructors, but the code to demonstrate it gets longer because we generally need at least a couple of different classes involved.
I have below class in VS2010-SP1, Ternary operator and if-else seems to be working differently for below code on getname method
template <int size=120> class StringBuf{
public:
StringBuf(const char* src){
strcpy(s,src);
}
// Copy from another StringBuf
StringBuf(const StringBuf& src){
strcpy(s,src.get());
}
// String access
operator const char*() const {return get();}
const char* get() const { return s ; }
private:
char s[size];
};
class MyPony{
StringBuf<10> name;
public:
MyPony(char* name_) : name(name_){}
const char* getname(bool bVal){
//if( bVal )
// return name;
//else
// return "Jimmy";
return (bVal==true) ? name : "Jimmy";
}
};
int main(){
MyPony pony("Pani");
const char* getname = pony.getname(true);
return 0;
}
If I use ternary operator getname() method makes a copy of name by calling copy constructor and then calls operator const char* on the temp copy.
If I change ternary operator into if-else the code just calls operator const char* without making a temp copy.
My understanding is that if else and ternary operator should behave the same, but why is this different behavior for this class? Is there something that I'm overlooking?
For ternary operator VS2005 seems to call operator const char* directly .
Of course: The type of the conditional expression a ? b : c is the common type of b and c, which in your case is StringBuf<10>. So either operand must first get converted to that type before the resulting value can be considered for return.
There conditional expression is an expression, and the if statement is a statement. They're different things for different purposes. Use the if statement in your situation.
You might wonder why the common type is StringBuf<10> and not char const *. That's because of C++11 5.16/3 ("Conditional operator"), which says that implicit conversions are considered. In your case, there is an implicit conversion from char const [6] (the type of "Jimmy") to StringBuf<10>, but not the other way round, so the common type is uniquely defined. For comparison, if you tried x ? name : static_cast<char const *>("Jimmy"), that would not compile.
With the following code, if I attempt to convert a template array to std::string, instead of the compiler using the expected std::string conversion method, it raises an ambiguity resolution problem (as it attempts to call the array conversion methods):
#include <iostream>
template<typename TemplateItem>
class TestA
{
public:
TemplateItem Array[10];
operator const TemplateItem *() const {return Array;}
operator const std::string() const;
};
template<>
TestA<char>::operator const std::string() const
{
std::string Temp("");
return Temp;
}
int main()
{
TestA<char> Test2;
std::string Temp("Empty");
Temp = Test2; //Ambiguity error. std::string or TemplateItem * ?
return 0;
}
What modification do I need to make to the code in order to make it so the code correctly and implicitly resolve to the std::string conversion function? Especially given the const TemplateItem * would be treated as a null-terminated array (which it won't likely be).
First, the reason you have ambiguity: you provide both conversion to char* and conversion to std::string const, and std::string likes them both.
By the way, before getting to your question, the const in operator std::string const was once a good idea, advocated by e.g. Scott Meyers, but is nowadays ungood: it prevents efficient moving.
Anyway, re the question, just avoid implicit conversions. Make those conversions explicit. Now I answered that in response to another SO question, and someone (I believe the person was trolling) commented that C++98 doesn't support explicit type conversion operators. Which was true enough, technically, but pretty stupid as a technical comment. Because you don't need to use the explicit keyword (supported by C++11), and indeed that's not a good way to make the conversions explicit. Instead just name those conversions: use named member functions, not conversion operators.
#include <iostream>
template<typename TemplateItem>
class TestA
{
public:
TemplateItem Array[10];
TemplateItem const* data() const { return Array; }
std::string str() const;
};
template<>
std::string TestA<char>::str() const
{
return "";
}
int main()
{
TestA<char> test2;
std::string temp( "Empty" );
temp = test2.str(); // OK.
temp = test2.data(); // Also OK.
}
Cheers & hth.
I will add, after thinking about it, here's the reasoning and what should be done:
The operator const TemplateItem *(); Should be deleted.
Why? There never will be an instance where you would want implicit conversion of TestA (or any template class) to a TemplateItem array with an unknown size - because this has absolutely no bounds checking (array could be sizeof 1 or 10 or 1000 or 0) and would likely cause a crash if a calling function or class received the array with no idea what size it is.
If the array is needed, either use the operator[] for direct items, or GetArray (which would signal the user intends to pass an unknown-length array).
Retain operator const std::string. Code will compile. Possible memory issues down the line averted.
(Alf for his efforts has been selected as the 'correct' answer, although this is the more logical option)
I'm trying to make a class, let's say MyClass, work under the following condition:
MyClass name = "everyone"; // Assigns "everyone" into a local string variable.
printf_s("Hello %s!", name); // Should output "Hello everyone!" without the quotes.
I've tried overloading operator const char*() as well as operator char*() but neither seem to do the trick.
If you overload it with operator const char*, you can explicitly cast it:
MyClass name = "everyone";
printf_s("Hello %s!", (const char*)name);
// prints "Hello everyone!"
And then it will behave properly. It doesn't work implicitly becase printf can take any type of parameter after the first one, so the compiler has no idea what to try to cast it to.
This assumes, of course, that operator const char* of your class returns the C-style string everyone.
As Tomalak Geret'kal noted in the comments, making your class implicitly castable to const char* could cause a lot of problems because it can cast itself without you knowing/wanting it to.
As Kerrek SB also pointed out, it's probably not worth making your class compatible with printf, since this is C++ after all. It would be better style to write an operator<< overload for ostream&s:
ostream& operator<<(ostream& rhs, const MyClass& c) {
rhs << c.name; // assuming the argument to the constructor
// is stored in the member variable name
return rhs;
}
MyClass name = "everyone";
cout << "Hello " << name << '!';
// prints "Hello everyone!"
You cannot "detect" the intention of being converted to a char const* when being passed into an ellipsis (...). Your object will just be put on the stack and you'll probably crash. This is different than if your object is passed in to a function that explicitly takes a char const*, in which case an implicit conversion operator can be triggered.
I would recommend going the same route as the standard library and rely as little as possible on implicit conversions. Instead, use a c_str() member or something.