#include <iostream>
#include <string>

// Abstract prototype class
class Prototype {
public:
    virtual ~Prototype() = default;
    // Clone method: return a deep copy of current object
    virtual Prototype* clone() const = 0;
    // Print object information (for verification)
    virtual void print() const = 0;
};

// Concrete prototype class: contains basic types and a dynamically allocated pointer member, demonstrating the necessity of deep copy
class ConcretePrototype : public Prototype {
private:
    int id;
    std::string name;
    int* data;          // Dynamically allocated pointer for demonstrating deep copy

public:
    // Constructor
    ConcretePrototype(int _id, const std::string& _name, int value)
        : id(_id), name(_name), data(new int(value)) {
        std::cout << "Constructing ConcretePrototype [id=" << id << ", name=" << name
                  << ", *data=" << *data << "]" << std::endl;
    }

    // Copy constructor (deep copy)
    ConcretePrototype(const ConcretePrototype& other)
        : id(other.id), name(other.name), data(new int(*(other.data))) {
        std::cout << "Copy constructing ConcretePrototype (deep copy) [id=" << id
                  << ", name=" << name << ", *data=" << *data << "]" << std::endl;
    }

    // Destructor: release dynamic memory
    ~ConcretePrototype() {
        delete data;
        std::cout << "Destructing ConcretePrototype [id=" << id << "]" << std::endl;
    }

    // Clone method: use copy constructor for deep copy
    Prototype* clone() const override {
        return new ConcretePrototype(*this);
    }

    // Print object internal state (including pointer address to verify deep copy)
    void print() const override {
        std::cout << "  id: " << id << ", name: " << name
                  << ", *data: " << *data << " (data address: " << data << ")" << std::endl;
    }

    // Modify members (for testing clone object independence)
    void setData(int value) {
        *data = value;
    }

    void setName(const std::string& newName) {
        name = newName;
    }
};

int main() {
    std::cout << "=== Prototype Pattern Demo (Deep Copy) ===" << std::endl;

    // 1. Create prototype object
    ConcretePrototype prototype(1, "Original", 100);
    std::cout << "\n[Prototype object]:" << std::endl;
    prototype.print();

    // 2. Create new object through cloning (no need to reconstruct)
    ConcretePrototype* clone1 = dynamic_cast<ConcretePrototype*>(prototype.clone());
    std::cout << "\n[Cloned object clone1] (initial state):" << std::endl;
    clone1->print();

    // 3. Modify cloned object's content
    clone1->setData(200);
    clone1->setName("Modified Clone");
    std::cout << "\n[After modifying clone1]:" << std::endl;
    std::cout << "Prototype object (should remain unchanged):" << std::endl;
    prototype.print();
    std::cout << "Cloned object clone1:" << std::endl;
    clone1->print();

    // 4. Clone again, demonstrating multiple independent copies
    ConcretePrototype* clone2 = dynamic_cast<ConcretePrototype*>(prototype.clone());
    std::cout << "\n[Cloned again to get clone2] (based on prototype):" << std::endl;
    clone2->print();

    // Modify clone2, verify it doesn't affect clone1 and prototype
    clone2->setData(300);
    clone2->setName("Another Clone");
    std::cout << "\n[After modifying clone2]:" << std::endl;
    std::cout << "clone1:" << std::endl;
    clone1->print();
    std::cout << "clone2:" << std::endl;
    clone2->print();

    // Clean up dynamically allocated objects
    delete clone1;
    delete clone2;

    std::cout << "\nProgram ended, all objects properly destructed." << std::endl;
    return 0;
}

results matching ""

    No results matching ""