提问人:ugo_capeto 提问时间:3/30/2023 最后编辑:ugo_capeto 更新时间:6/6/2023 访问量:184
C++ 中的替代复制构造函数
alternative copy constructor in c++
问:
编辑: 我将介绍一些设计糟糕的类,这是一个老问题,从那时起我就成长为一名程序员......
假设我有一个具有某种状态的类,并且使用一个仅使用该状态的一部分的方法,您将明白我的意思:
#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;
};
如果你能原谅我这个愚蠢的例子,我想指出也只使用,所以我当时的想法是创建一个函数来创建一个新实例,该实例只复制方法中所需的元素,我想到了这样的事情:time_the_method
data1
MyClass
// 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);
我创建了当时所谓的“自定义复制构造函数”(这个名字激怒了一些人),它需要一个虚拟变量来更改构造函数的签名。
此外,虚拟变量实际上将来可能会有一些用处,也许可以切换到一个,这样我就可以告诉编译器,可能在编译时使用模板,当我想要在我的成员函数中进行部分复制时,我需要哪个“自定义复制构造函数”。enum class
我有这个想法是因为我注意到,在覆盖增量前和增量后运算符时,我们必须做类似的事情:
MyClass operator++(int); // pre increment
MyClass& operator++(); // post increment
通过更改签名,编译器能够知道要调用哪个签名。
我还意识到,这种技术更适合于操作员重载,而不是构造函数重载。 这就是为什么我问是否有人在这方面有任何改进。
我意识到,如果你必须做这样的事情,很可能类本身设计得很差,它处理了太多的状态,所以需要代码重构。但无论如何,探索次优解决方案并没有什么坏处,也许只是为了理解为什么最优解决方案真的更好......
答:
我确实明白您的代码只是一个示例,尽管我不明白是什么。请注意,它不是复制构造函数。复制构造函数不是别的东西。这种区别很重要,因为大多数情况下,复制构造函数是在创建复制时隐式调用的:MyClass(const MyClass& other, int)
MyClass(const MyClass&)
void foo(Example);
Example a;
Example b = a; // calls the copy constructor
foo(b); // calls the copy constructor
MyClass(const MyClass& other, int)
不是复制构造函数。如果你对此感到满意,那就好了。它只是不是一个在制作副本时会隐式调用的构造函数。
我知道传递虚拟变量与重载前缀和后缀 ++运算符的过程相同:
利用过载分辨率是个好主意。虽然你不会得到与. 需要特殊的语言支持来区分 和 。构造函数无法获得该支持。++
++
operator++()
operator++(int)
我不完全确定您是否要使某些成员保持未初始化状态。你不应该那样做。而是重新考虑你的设计。如果在某些地方做得比你需要的多,那么这就是设计的味道。很可能是为一个班级做了太多的事情(参见单一责任原则)。MyClass
MyClass
但是,如果您想要一个只能由一个函数访问的某种复制的构造函数,则可以这样做:
#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
}
请注意如何仅访问而不是访问可能具有的任何私有部分。foo
MyClass(const Proxy& p)
MyClass
评论