How to create spy class against clone idiom in C ++

Coming from the Java / PHP world, I'm still new to C ++. Some simple things to do in other languages ​​are a little harder to do in C ++.

My main problem is as follows. Right now I have a class (ie, "Something") for which the constructor is introduced with the dependency of a virtual class (ie, children of the "base"). The constructor then saves this entered instance in the class field unique_ptr<Base>(using the clone idiom). This works well at the application level, everything works as expected. Here is a sample code:

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. , Derived Something Derived , .

, , , Something SpyDerived, . . .

MSVC 2015 . , , ++, copy/move .

.

+4
1

, ?

, , .

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, , ?

Simple! , !


, ++ . , clone.

, 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;
};

++ . , , , .

, :

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, derived_ref , Something .

+3

Source: https://habr.com/ru/post/1690797/


All Articles