Assuming I have a (trivial) class that wraps normal int type in C++ for random integers, how can I use an instance of this class like an integer when indexing an array or picking a character from a string?
If it's a matter of operator overloading, then which operator?
As a specific example, I have a Random class and I pick characters at random locations in a string like this:
string chars = "whatever";
Random R = Random(0, chars.length());
other_chars += chars.at(R.getValue());
But instead, I'd rather have other_chars += chars.at(R); But how?
You need a user defined conversion operator.
class Random
{
int x_;
public:
operator int() const { return x_; }
};
Have you tried overloading operator int() inside the wrapper Random. I believe it should be something like,
class Random
{
int value;
public:
// ... constructors and operator =
operator int () const { return value; }
};
You need typecast operator overloading: operator int() { return _value; }.
Here is more explanation.
Related
I have a uni assignment in which I have to create a custom template which acts as an array of doubles. It also has to implement a sorting algorithm which sorts the elements in descending order. I designed the template so it has an internal array of doubles with the length declared by the user (MyArray<10> contains a double array with a length of 10). My custom array will only be filled up with doubles in ascending order from myArr[0] and values won't be changed once assigned, but they can be any value so I can't have a magic constant to keep track of them. Instead I have to check the number of assignments to the array so when I call the sort() method, it knows which is the last changed element.
My subscript operator:
Proxy &operator[](int elem) {
if(elem > arr_size - 1) {
throw std::out_of_range("Out of range");
}
std::cout << "a" << std::endl;
return Proxy(*this, elem);
}
And the proxy class which is inside the F8 class:
class Proxy {
private:
F8 &a;
int id;
public:
Proxy(F8 &a, int id) { this.a = a; this.id = id; };
int& operator=(int x) { curr_num++; return a.arr[id]; }
};
Is there a way to check if operator[] is in an assignment (or if it is an lvalue)? I have tried it with a proxy class but it just seems too complicated for a beginner C++ class and that way I have to implement all of the operators (the values get compared etc, so when with operator[] I return a double it can be compared directly, but when I return the Proxy class, the compiler gives an error for every operator because they don't exist, and the task doesn't ask me to implement all the operators needed for comparison).
Thank you for your time!
Edit: I get the following error when I try to return a proxy class in which I can keep track of the assignment operator:
error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'F8<433>::Proxy')
Also to make things clear: the array will be filled in the ascending order of indexes, so after I assign a value to myArr[0] comes myArr[1].
I seems to me like you are looking for a user defined conversion.
class Proxy {
private:
F8 &a;
int id;
public:
Proxy(F8 &a, int id) { this.a = a; this.id = id; };
int& operator=(int x) { curr_num++; return a.arr[id]; }
operator int() const { return a.arr[id]; }
// ^ int or double? You say double but your example code seems to be using int.
};
Not sure how/what your assignment operator is supposed to do. Right now it's only returning a value from your array but not actually assigning anything.
What about something like
int& operator=(int x) { curr_num++; a.arr[id]=x; return a.arr[id]; }
I have a project that wants me to make a BigNum class in c++ (university project)
and it said to overload operator bracket for get and set
but the problem is if the set was invalid we should throw an exception the invalid is like
BigNum a;
a[i]=11;//it is invalid because its >9
in searching I found out how to make the set work
C++ : Overload bracket operators [] to get and set
but I didn't find out how to manage setting operation in c# you easily can manage the set value what is the equivalent of it in c++
to make it clear in C# we can say
public int this[int key]
{
set
{
if(value<0||value>9)throw new Exception();
SetValue(key,value);
}
}
New Answer
I have to rewrite my answer, my old answer is a disaster.
The check should happen during the assignment, when the right hand side (11) is available. So the operator which you need to overload is operator=. For overloading operator=, at least one of its operands must be an user defined type. In this case, the only choice is the left hand side.
The left hand side we have here is the expression a[i]. The type of this expression, a.k.a the return type of operator[], must be an user defined type, say BigNumberElement. Then we can declare an operator= for BigNumberElement and do the range check inside the body of operator=.
class BigNum {
public:
class BigNumberElement {
public:
BigNumberElement &operator=(int rhs) {
// TODO : range check
val_ = rhs;
return *this;
}
private:
int val_ = 0;
};
BigNumberElement &operator[](size_t index) {
return element_[index];
}
BigNumberElement element_[10];
};
OLD answer
You can define a wapper, say NumWapper, which wraps a reference of BigNum's element. The operator= of BigNum returns the wrapper by value.
a[i]=11;
is then something like NumWrapper x(...); x = 11. Now you can do those checks in the operator= of NumWrapper.
class BigNum {
public:
NumWrapper operator[](size_t index) {
return NumWrapper(array_[index]);
}
int operator[](size_t index) const {
return array_[index];
}
};
In the NumWrapper, overload some operators, such as:
class NumWrapper {
public:
NumWrapper(int &x) : ref_(x) {}
NumWrapper(const NumWrapper &other) : ref_(other.ref_) {}
NumWrapper &operator=(const NumWrapper &other);
int operator=(int x);
operator int();
private:
int &ref_;
};
You can also declare the NumWrapper's copy and move constructor as private, and make BigNum his friend, for preventing user code from copying your wrapper. Such code auto x = a[i] will not compile if you do so, while user code can still copy the wrapped value by auto x = static_cast<T>(a[i]) (kind of verbose though).
auto &x = a[i]; // not compiling
const auto &x = a[i]; // dangerous anyway, can't prevent.
Seems we are good.
These is also another approach: store the elements as a user defined class, say BigNumberElement. We now define the class BigNum as :
class BigNum {
// some code
private:
BigNumberElement array_[10];
}
We need to declare a whole set operators for BigNumberElement, such as comparison(can also be done through conversion), assignment, constructor etc. for making it easy to use.
auto x = a[i] will now get a copy of BigNumberElement, which is fine for most cases. Only assigning to it will sometimes throw an exception and introduce some run-time overhead. But we can still write auto x = static_cast<T>(a[i]) (still verbose though...). And as far as I can see, unexpected compile-time error messages is better than unexpected run-time exceptions.
We can also make BigNumberElement non-copyable/moveable... but then it would be the same as the first approach. (If any member functions returns BigNumberElement &, the unexpected run-time exceptions comes back.)
the following defines a type foo::setter which is returned from operator[] and overloads its operator= to assign a value, but throws if the value is not in the allowed range.
class foo
{
int data[10];
public:
void set(int index, int value)
{
if(value<0 || value>9)
throw std::runtime_error("foo::set(): value "+std::to_string(value)+" is not valid");
if(index<0 || index>9)
throw std::runtime_error("foo::set(): index "+std::to_string(index)+" is not valid");
data[index] = value;
}
struct setter {
foo &obj;
size_t index;
setter&operator=(int value)
{
obj.set(index,value);
return*this;
}
setter(foo&o, int i)
: obj(o), index(i) {}
};
int operator[](int index) const // getter
{ return data[index]; }
setter operator[](int index) // setter
{ return {*this,index}; }
};
If what you are trying to do is overload [] where you can input info like a dict or map like dict[key] = val. The answer is actually pretty simple:
lets say you want to load a std::string as the key, and std::vector as the value.
and lets say you have an unordered_map as your underlying structure that you're trying to pass info to
std::unordered_map<std::string, std::vector<double>> myMap;
Inside your own class, you have this definition:
class MyClass{
private:
std::unordered_map<std::string, std::vector<double>> myMap;
public:
std::vector<double>& operator [] (std::string key) {
return myMap[key];
}
}
Now, when you want to load your object, you can simply do this:
int main() {
std::vector<double> x;
x.push_back(10.0);
x.push_back(20.0);
x.push_back(30.0);
x.push_back(40.0);
MyClass myClass;
myClass["hello world"] = x;
double x = myClass["hello world"][0]; //returns 10.0
}
The overloaded [] returns a reference to where that vector is stored. So, when you call it the first time, it returns the address of where your vector will be stored after assigning it with = x. The second call returns the same address, now returning the vector you had input.
I'm doing a very small and simple Integer class wrapper in C++, which globaly looks like this:
class Int
{
...
private:
int value;
...
}
I handled almost all the possible assignements, but I don't find out what kind of operator I have to use to get native left assignement.
eg:
Int myInteger(45);
int x = myInteger;
You might want a conversion operator to convert to int:
class Int
{
public:
operator int() const { return value; }
...
};
This allows the following initialization of an int
int x = myInteger;
In C++11, you can decide whether you restrict that conversion to int, or whether you allow further conversions from int to something else. To restrict to int, use an explicit conversion operator:
explicit operator int() const { return value; }
although it is probably not necessary in this case.
I need to modify the ordering of my C++ class members. For example:
class B {
public:
int i;
int j;
int k;
...
};
becomes
class B {
public:
int j;
int k;
int i;
...
};
The problem is there are weird codes in my large code bases that depend on relative location of the class members. For example some functions would assume address of member j is smaller than that of member k.
Is there any CASE tool that can help me to identify any code that read the address of a class member?
I am not aware of any tool that solve your problem, but I would define a class which supports all operators for int type and which overloads ampersand operator so that the result of the operator cannot be casted to a pointer. Then I'd use this class instead of int in your class member definitions and look at places where compiler gives errors.
Something like
class IntWrapper {
public:
IntWrapper() { }
IntWrapper(const int x) { } // don't care about implementation as we
operator int() const { return 0; } // want compile-time errors only
IntWrapper& operator ++() { return *this; }
IntWrapper& operator ++(int) { return *this; }
...
void operator &() const { } // make it void so it would cause compiler error
};
And then:
class B {
public:
IntWrapper i;
IntWrapper j;
IntWrapper k;
...
};
This will not help against using boost::addressof function or some dirty reinterpret_cast of a reference, but addressof is probably never used at all in your project, as well as the reinterpret_cast<char&> trick (who would use it for plain integers?).
You should also care about taking an address of the whole object of B class.
I am trying to overload part of my class to a string and I can't get the overloading to work. Alternatively, I will also have a long long overload, but I just assume that it will be the same excepted for long long instead of string.
class FileData
{
public:
string extensions_;
unsigned long long containsBytes_;
};
string& operator = (string& s , FileData& fd)
{
s= fd.extensions_;
return s;
}
string extName = fileVector[0];
The error I keep getting is ERROR:'operator=' must be a member function.
I also tried using istream but that also didn't work.
Anybody know how I could go about this?
To be able to assign to a string from your class, you'll need a conversion operator:
class FileData
{
public:
// Conversion to string
operator string() const {return extensions_;}
string extensions_;
unsigned long long containsBytes_;
};
You can only overload the assignment operator as a member of your class, for the purpose of assigning to an object of that class.
You can't overload the operator= of std::string. What you probably want is a cast operator:
class FileData
{
public:
string extensions_;
unsigned long long containsBytes_;
operator string()
{
return extensions_;
}
}