I am reviewing operator overloading in C++. Just for fun I am implementing a BigInt
class.
The first operator I want to overload for it is the addition operator. I have decided to overload this operator as a friend non-member function. Here's a MWE of this code:
#include <cassert>
#include <iostream>
#include <string>
class BigInt{
public:
friend BigInt operator+(const BigInt &bi1, const BigInt &bi2);
BigInt() {}
explicit BigInt(const std::string &in) {
if (in.size() != 0) {
for (auto cc = in.rbegin(); cc != in.rend(); ++cc) {
value_.push_back(*cc);
}
}
}
std::string value() {
std::string actual_value{}; // Reversed string.
for (auto cc = value_.rbegin(); cc != value_.rend(); ++cc) {
actual_value.push_back(*cc);
}
return actual_value;
}
private:
std::string value_; // String of digits as characters.
};
BigInt operator+(const BigInt &bi1, const BigInt &bi2) {
BigInt result{};
result.value_ = "4421";
return result;
}
int main() {
std::cout << "Test addition operator... ";
std::string number{"1234"}; // Number 1,234.
BigInt mm(number);
std::string number_ten{"10"}; // Number 10.
BigInt nn(number_ten);
BigInt mm_nn = mm + nn;
std::string expected_result{"1244"}; // 1,234 + 10 = 1,244.
assert(mm_nn.value() == expected_result);
std::cout << "ok." << std::endl;
}
This code mocks the behavior of the addition. It compiles and runs. Yet when I add a copy constructor for the BigInt
class, this codes stops working. I.e. if I add this to the class declaration:
explicit BigInt(const BigInt &in): value_(in.value_) {}
The code does not even compile. The addition function as coded returns a copy of a constructed instance of BigInt
. For this a copy constructor must be defined. If I do not define it myself, then the compiler will do so. What does the compiler produce that I am not producing with the added copy constructor? Here's the compilation error I get:
$ g++ -std=c++14 -g mwe.cpp
mwe.cpp: In function ‘BigInt operator+(const BigInt&, const BigInt&)’:
mwe.cpp:34:10: error: no matching function for call to ‘BigInt::BigInt(BigInt&)’
return result;
^
mwe.cpp:9:3: note: candidate: BigInt::BigInt()
BigInt() {}
^
mwe.cpp:9:3: note: candidate expects 0 arguments, 1 provided
mwe.cpp: In function ‘int main()’:
mwe.cpp:44:23: error: no matching function for call to ‘BigInt::BigInt(BigInt)’
BigInt mm_nn = mm + nn;
^
mwe.cpp:9:3: note: candidate: BigInt::BigInt()
BigInt() {}
^
mwe.cpp:9:3: note: candidate expects 0 arguments, 1 provided
From it, it seems like the compiler expects a copy constructor that I have not provided. Now... IF I REMOVE the explicit
keyword, everything works. However, I have seen implementations with explicit copy constructor, for example: Explicit copy constructor
What am I missing? Why can't I make this copy constructor explicit while overloading the addition operator? Should, in general, copy constructors be made explicit?
Making the copy constructor explicit
does not make sense. Remove it.
BigInt(const BigInt &in): value_(in.value_) {}
explicit
Copy ConstructorMaking a copy constructor explicit
makes returning an object from a function impossible.
Let's simplify your code to the following:
struct BigInt
{
BigInt() {}
explicit BigInt(const BigInt &in) {}
};
BigInt operator+(const BigInt &bi1, const BigInt &bi2)
{
BigInt result;
return result;
}
int main() {}
In the line return result
, the compiler relies on the copy constructor to return an object. When the copy constructor is explicit, there is no way for a BigInt
to be constructed as the return value.
Trying to use:
BigInt operator+(const BigInt &bi1, const BigInt &bi2)
{
BigInt result;
return BigInt(result);
}
is futile since that is equivalent to:
BigInt operator+(const BigInt &bi1, const BigInt &bi2)
{
BigInt result;
BigInt result1(result);
return result1;
}
The problem continues to be there no matter what you do in the function.