Edit: I am going to introduce some badly designed class, this was an old question and I have grown as a programmer since then...
Let's say I have a class with some state and with a method that only uses a part of that state, you will see what I mean:
#include <thread>
#include <chrono>
class MyClass
{
public:
MyClass(double _1, double _2, double _3)
: data1(_1)
, data2(_2)
, data3(_3)
{}
void only_uses_data1()
{
for (int i = 0; i < data1; ++i)
std::this_thread::sleep_for(std::chrono::seconds(1));
data1 = 0; // modifies state
}
auto time_the_method() const // this can't modify the instance
{
MyClass copy = *this;
auto t1 = std::chrono::high_resolution_clock::now();
copy.only_uses_data1();
auto t2 = std::chrono::high_resolution_clock::now();
return t2 - t1;
}
private:
double data1, data2, data3;
};
If you can forgive me for the dumb example, I want to point out that time_the_method
only uses data1
as well, so my thought at the time was to create a function that creates a new MyClass
instance that only copied the element that was needed in the method, and I thought of something like this:
// inside MyClass definition
private:
explicit MyClass(const MyClass& other, int) // takes a dummy int
: data1(other.data1) // copies the necessary data
{}
// usage
MyClass copy(*this, 0);
I created what I called at the time a "custom copy constructor" (this name enraged a few people), that takes a dummy variable to change the signature of the constructor.
Furthermore, the dummy variable could actually have some use in the future, maybe switching to an enum class
instead, this way I could tell the compiler, possibly at compile time with templates, which "custom copy constructor" I need when I want a partial copy in my member functions.
I had this idea because I noticed that when overriding the pre and post increment operators, we have to do something similar:
MyClass operator++(int); // pre increment
MyClass& operator++(); // post increment
By changing the signature, the compiler is able to know which one to call.
I also realized that this technique was far more appropriate for operator overloading than for constructor overloading. That is why I asked if anyone had any improvements on this.
I realized that if you have to do something like this, probabily the class itself is poorly designed and it handles too much state, so a code refactor is needed. But anyway, it does not hurt to explore suboptimal solutions, maybe just to understand why the optimal one really is better...
I do understand that your code is just an example, though I do not understand for what. Note that MyClass(const MyClass& other, int)
is not a copy constructor. A copy constructor is MyClass(const MyClass&)
not something else. This distinction is important, because most of the time the copy constructor is called implicitly when you make a copy:
void foo(Example);
Example a;
Example b = a; // calls the copy constructor
foo(b); // calls the copy constructor
MyClass(const MyClass& other, int)
is not a copy constructor. If you are ok with that then ok. It's just not a constructor that will be invoked implicitly when a copy is made.
I know that passing a dummy variable is the same process for overloading the prefix and postfix ++operator:
Making use of overload resolution is a good idea. Though you wont get the same effect as with ++
. ++
needs special language support to distinguish between operator++()
and operator++(int)
. Your constructor cannot get that support.
I am not entirely sure if you want to keep certain members uninitialized. You should not do that. Rather reconsider your design. If MyClass
does more than you need in certain places then thats a design smell. Very likely MyClass
is doing too much for a single class (cf. single responsibility principle).
However, if you want a constructor that does some sort of copying accessible only to one function, you can do this:
#include <iostream>
struct MyClass;
void foo(MyClass&);
struct Proxy {
MyClass& object;
private:
Proxy(MyClass& object) : object(object) {}
friend void foo(MyClass&);
};
struct MyClass {
MyClass() = default;
MyClass(const Proxy& p) {} // implement special copy here
MyClass(const MyClass&) = default; // copy constructor
};
void foo(MyClass& a) {
MyClass b = Proxy(a);
}
int main() {
MyClass a;
MyClass b = Proxy(a); // fails to compile
}
Note how foo
gets only access to MyClass(const Proxy& p)
but not to any private parts that MyClass
might have.