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
explicitdoes not make sense. Remove it.Conceptual Problem With
explicitCopy ConstructorMaking a copy constructor
explicitmakes returning an object from a function impossible.Let's simplify your code to the following:
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 aBigIntto be constructed as the return value.Trying to use:
is futile since that is equivalent to:
The problem continues to be there no matter what you do in the function.