#include #include #include #include #include #include // Forward declarations class INode; class ILink; class ILinkMixin; using NodePtr = std::shared_ptr; using LinkPtr = std::shared_ptr; // --- ИНТЕРФЕЙСЫ --- class ILinkMixin { public: virtual ~ILinkMixin() = default; virtual void linkChild(const NodePtr& child) = 0; virtual void unlinkParent() = 0; virtual LinkPtr getLink() = 0; }; class INode : public ILinkMixin { public: ~INode() override = default; virtual const std::string& name() const = 0; // УБРАНО: const. Этот метод используется для получения указателя, // который может участвовать в не-константных операциях. virtual NodePtr getSelf() = 0; }; class ILink { public: virtual ~ILink() = default; virtual NodePtr getNode() const = 0; virtual LinkPtr getParent() const = 0; virtual void setParent(const LinkPtr& parent) = 0; virtual const std::vector& getChildren() const = 0; virtual void addChild(const LinkPtr& child) = 0; virtual void removeChild(const LinkPtr& child) = 0; }; // --- РЕАЛИЗАЦИИ LINK --- class BaseLink : public ILink { public: explicit BaseLink(NodePtr node) : owner_node_(node) {} NodePtr getNode() const override { return owner_node_.lock(); } LinkPtr getParent() const override { return parent_.lock(); } void setParent(const LinkPtr& parent) override { parent_ = parent; } const std::vector& getChildren() const override { return children_; } void removeChild(const LinkPtr& child) override { children_.erase(std::remove(children_.begin(), children_.end(), child), children_.end()); } protected: std::vector children_; std::weak_ptr owner_node_; std::weak_ptr parent_; }; class LeafLink : public BaseLink { public: using BaseLink::BaseLink; void addChild(const LinkPtr&) override { throw std::logic_error("LeafLink cannot have children"); } }; class OneToManyLink : public BaseLink { public: using BaseLink::BaseLink; void addChild(const LinkPtr& child) override { children_.push_back(child); } }; // --- CRTP МИКСИН-РЕАЛИЗАЦИЯ --- template class LazyLinkMixin : public INode { public: void linkChild(const NodePtr& childNode) override { lazyInit(); upgradeLinkIfNeeded(); LinkPtr childLink = childNode->getLink(); childLink->setParent(link_); link_->addChild(childLink); } void unlinkParent() override { lazyInit(); LinkPtr parentLink = link_->getParent(); if (!parentLink) return; parentLink->removeChild(this->getLink()); link_->setParent(nullptr); downgradeLinkIfPossible(); } LinkPtr getLink() override { lazyInit(); return link_; } protected: // УБРАНО: const. Возвращаем неконстантный указатель. virtual std::shared_ptr getShared() = 0; // УБРАНО: const. Соответствует базовому классу. NodePtr getSelf() override { return getShared(); } private: void lazyInit() { if (!link_) { link_ = std::make_shared(getSelf()); } } void upgradeLinkIfNeeded() { if (!std::dynamic_pointer_cast(link_)) return; auto oldParent = link_->getParent(); link_ = std::make_shared(getSelf()); link_->setParent(oldParent); } void downgradeLinkIfPossible() { if (link_->getChildren().empty()) { auto oldParent = link_->getParent(); link_ = std::make_shared(getSelf()); link_->setParent(oldParent); } } LinkPtr link_; }; // --- КОНКРЕТНЫЙ УЗЕЛ --- // УБРАНО: final. Теперь от класса можно наследоваться. class SimpleNode : public LazyLinkMixin, public std::enable_shared_from_this { public: static NodePtr create(std::string name) { // Теперь эта структура может легально наследоваться от SimpleNode struct EnableMakeShared : public SimpleNode { EnableMakeShared(std::string n) : SimpleNode(std::move(n)) {} }; return std::make_shared(std::move(name)); } const std::string& name() const override { return name_; } protected: // УБРАНО: const. Теперь возвращается неконстантный shared_ptr, как и ожидается. std::shared_ptr getShared() override { return shared_from_this(); } private: friend struct std::enable_shared_from_this; friend class LazyLinkMixin; explicit SimpleNode(std::string name) : name_(std::move(name)) {} std::string name_; }; // --- УТИЛИТА ДЛЯ ВЫВОДА --- void printTree(const NodePtr& startNode, int indent = 0) { if (!startNode) return; for (int i = 0; i < indent; ++i) std::cout << " "; std::cout << startNode->name() << "\n"; LinkPtr nodeLink = startNode->getLink(); for (const auto& childLink : nodeLink->getChildren()) { printTree(childLink->getNode(), indent + 1); } } // --- MAIN --- int main() { auto root = SimpleNode::create("Root"); auto child1 = SimpleNode::create("Child1"); auto child2 = SimpleNode::create("Child2"); root->linkChild(child1); root->linkChild(child2); auto subchild = SimpleNode::create("SubChild"); child1->linkChild(subchild); printTree(root); std::cout << "\nUnlinking Child1...\n"; child1->unlinkParent(); printTree(root); return 0; }