gpt4 book ai didi

c++ - 如何在 C++ 中针对克隆习惯创建 spy 类

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:59:38 24 4
gpt4 key购买 nike

来自 Java/PHP 世界,我对 C++ 还是个新手。一些用其他语言做的简单事情用 C++ 做起来有点棘手。

我的主要问题如下。现在,我有一个类(即“Something”),构造函数为其注入(inject)了虚拟类依赖项(即“Base”的子级)。然后,构造函数将这个注入(inject)的实例存储在 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;
};

但为了确保它确实如此,我编写了单元测试来测试它的行为。在那些测试中,我想断言注入(inject)的依赖项方法实际上被调用了。所以从逻辑上讲,注入(inject)“ spy ”依赖项应该可以解决问题。

这是我一开始做的:

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 .我明白了 Derived Something 中的实例是 Derived 的新拷贝而不再是在 main 函数中创建的那个。

所以基本上,我在这里想要实现的是拥有 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所有权应该从调用者转移到 something 类。该转移是通过 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();
}

Somethingderived 的所有者, 非拥有引用 derived_ref如果 something 将指向死对象之前就死了。

关于c++ - 如何在 C++ 中针对克隆习惯创建 spy 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47817822/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com