如何针对C 中的克隆成语创建间谍类
How to create a spy class against the clone idiom in C++
来自Java/PHP世界,我仍然是C 的新手。在其他语言中要做的一些简单的事情在C 中要做一些棘手。
我的主要问题是以下内容。现在,我有一个类(即"某物"),为构造函数注入了虚拟级别的依赖性(即"基础"的孩子)。然后,构造函数将此注入的实例存储在unique_ptr<Base>
类字段中(使用克隆成语)。这在应用程序级别上效果很好,一切似乎都按预期工作。这是示例代码:
class Base {
public:
virtual std::unique_ptr<Base> clone() = 0;
virtual void sayHello() const = 0;
};
class Something {
public:
explicit Something(Base &base) { this->base = base.clone(); }
void sayHello() const { base->sayHello(); }
private:
std::unique_ptr<Base> base;
};
但是,为了确保确实如此,我编写了单元测试以测试其行为。在这些测试中,我想确定实际调用了注入的依赖性方法。因此,从逻辑上讲,注入"间谍"依赖性应该可以解决问题。
这是我起初所做的:
class SpyDerived : public Base {
public:
explicit SpyDerived() = default;
SpyDerived(const SpyDerived &original) { this->someState = original.someState; }
std::unique_ptr<Base> clone() override { return std::make_unique<SpyDerived>(*this); }
void sayHello() const override { std::cout << "My state: " << someState << std::endl; }
void setSomeState(bool value) { this->someState = value; }
private:
bool someState = false;
};
这是我使用的主要功能:
int main() {
SpyDerived derived;
Something something(derived);
derived.setSomeState(true);
something.sayHello();
}
出于明显的原因,someState
打印值始终为false
。我知道Something
中的Derived
实例是Derived
的新副本,不再是在主函数中创建的副本。
基本上,我在这里要实现的目标是让Something
类始终使用在主函数中创建的SpyDerived
实例。有什么办法可以做这项工作。我试图避免仅出于测试目的更改设计。
我正在使用MSVC 2015来编译代码。请记住,聪明的指针,C 成语,复制/移动构造函数对我来说是相当新的概念。
感谢您的帮助。
好吧,您想克隆您的实例,还是简单地引用该实例?
克隆成语是制作以复制类的实例,使新实例独立于旧实例。
您基本上是按照PHP的术语来进行的:
<?php
interface Base {
public function sayHello();
}
class SpyDerived implements Base {
private $someState = false;
public function sayHello() {
echo 'My state: ' . $this->someState;
}
}
class Something {
public __construct(Base $base) { $this->base = clone $base; }
public function sayHello() { $this->base->sayHello(); }
private $base = null;
}
$derived = new SpyDerived;
$something = new Something($derived);
$derived->setSomeState(true);
$something->sayHello();
?>
你看到了吗?$base
被克隆。 Something::$base
是复制。
所以在PHP中,您将如何解决该问题?
简单!删除该克隆,没有副本!
好吧,在C 中,这是同一件事。如果您有对象指针并且不想克隆它,则实际上不要调用克隆方法。
我们将把您的课程更改为PHP,包含对对象的引用。我们将首先使Something
包含一个非所有参考:
class Something {
public:
explicit Something(Base& b) : base{b} { }
void sayHello() const { base.sayHello(); }
private:
// we simply contain a reference to the base
Base& base;
};
在C 中,参考不拥有对象。如果对象被破坏,则所有指向该对象的参考都将指向一个死对象。
您会注意到,您的测试保持不变并起作用:
int main() {
SpyDerived derived;
Something something(derived);
derived.setSomeState(true);
something.sayHello();
}
如果您要Something
成为Base
的所有者,请使用std::unique_ptr<Base>
:
class Something {
public:
explicit Something(std::unique_ptr<Base> b) : base{std::move(b)} { }
void sayHello() const { base->sayHello(); }
private:
std::unique_ptr<Base> base;
};
注意base
的所有权应从呼叫者转移到某物类。该转移是通过std::move
表达的,因为我们正在移动该资源的所有权。
然后在您的测试中:
int main() {
auto derived = std::make_unique<SpyDerived>();
// We want to keep a non-owning reference of derived
// The star (*) operator of std::unique_ptr returns a reference to the pointed object
auto& derived_ref = *derived;
// We transfer the ownership of derived to the `Something`
Something something(std::move(derived));
// Since derived is a reference to the object pointed by our pointer,
// It will affect the value we found in `Something`, because they are
// both pointing to the same instance.
derived.setSomeState(true);
something.sayHello();
}
由于Something
是derived
的所有者,如果something
死亡,则非持有参考derived_ref
将指向一个死对象。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 使用std::multimap迭代器创建std::list
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 使用CMake创建QML插件
- 如何在c++中为模板函数实例创建快捷方式
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- OpenCV EqualizeHist()从彩色图像创建黑白图像
- 试图在visual studio上用C++创建一个桌面应用程序
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 如何在C++20中创建模板别名的推导指南
- 如何为模板化对象创建模板向量?VS正在投掷C3203
- 如何创建一个空的全局类并在启动时实例化它
- 无法创建抽象类的实例
- 链接到自行创建的dll失败
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何在C++类内存结构中创建"spacer"?
- 终端不会为C++文件创建.exe文件吗
- 如何针对C 中的克隆成语创建间谍类