C+中的父子类关系+;带指针 我应该如何在C++中实现父子关系?我希望父母一次只能有一个活跃的孩子,但我也希望孩子“知道”自己的父母是谁 子类是抽象的,因此只能在父类中声明指向它的指针 Child有一个指向其父的受保护指针,但我不希望它拥有该指针,我不希望实现者删除父指针指向的内存 指针重新分配呢?父级的活动子级可以更改。此时,我将删除当前子指针后面的内存,并将其设置为新的子指针
我希望C+中的父子类关系+;带指针 我应该如何在C++中实现父子关系?我希望父母一次只能有一个活跃的孩子,但我也希望孩子“知道”自己的父母是谁 子类是抽象的,因此只能在父类中声明指向它的指针 Child有一个指向其父的受保护指针,但我不希望它拥有该指针,我不希望实现者删除父指针指向的内存 指针重新分配呢?父级的活动子级可以更改。此时,我将删除当前子指针后面的内存,并将其设置为新的子指针,c++,pointers,C++,Pointers,我希望父项拥有当前子项指针,并在更改时释放它,但我不希望子项拥有其父项指针 我应该使用智能指针吗?我来自C#背景,在那里很容易做到这一点。有什么我没听说过的模式吗 这是我目前掌握的代码: #pragma once class Child; class Parent { private: Child* current_child = nullptr; public: void ChangeChild(Child* child_ptr); }; // Parent.cpp vo
父项
拥有当前子项
指针,并在更改时释放它,但我不希望子项
拥有其父项
指针
我应该使用智能指针吗?我来自C#背景,在那里很容易做到这一点。有什么我没听说过的模式吗
这是我目前掌握的代码:
#pragma once
class Child;
class Parent
{
private:
Child* current_child = nullptr;
public:
void ChangeChild(Child* child_ptr);
};
// Parent.cpp
void Parent::ChangeChild(Child* child_ptr)
{
if (child_ptr == nullptr)
{
// throw
}
delete current_child;
current_child = child_ptr;
}
和子类
抽象类:
#pragma once
#include "Parent.h"
class Child
{
protected:
Parent* parent;
public:
Child(Parent* parent_ptr)
{
parent = parent_ptr;
}
virtual void Do() = 0;
};
我不确定我是否得到了您设计中的所有约束,但以下是一个开始:
#包括
#包括
#包括
类节点{
公众:
///@brief一个没有父节点和子节点的节点。
显式Node()noexcept:m_child{nullptr},m_parent{nullptr}{
std::cout child()->set_child(std::make_unique());
//不变量
断言(root->child()->child()->parent()==root->child());
}
可能的产出:
$ clang++ example.cpp -std=c++2a -Wall -Wextra -Werror -fsanitize=address
$ ./a.out
Node(0x6020000000d0)
Node(0x6020000000f0)
Node(0x602000000110)
~Node(0x6020000000f0)
Node(0x602000000130)
~Node(0x6020000000d0)
~Node(0x602000000110)
~Node(0x602000000130)
关于这个话题,我看过的最好的演讲可能是赫伯·萨特(Herb Sutter)的演讲。看吧。他详细介绍了何时使用不同的指针(
共享指针
,唯一指针
,弱指针
,“原始”指针和引用)。他还讨论了与深度递归设计相关的递归销毁问题。假设父对象被销毁时,每个子对象都将被销毁,您只需使用std::unique_ptr
。为方便起见,您可以提供一个通过po的set_Child
函数您可以将其扩展为可变模板,这样它也可以传递任意数量的参数-如果对您有用的话,谷歌“完美转发函数”
(std::shared_ptr
和std::weak_ptr
如果允许Child
派生对象比其父对象长寿,并且可能会回调到Child
函数,以了解父对象是否仍然存在。)
代码也可在
#包括
#包括
结构父级;
结构子对象{
虚拟~Child(){}
子(父*p_父):p_父{p_父}{}
虚int f()常量{return 0;}
家长*p_家长u;
};
结构父级
{
std::唯一的\u ptr p\u子\uu;
//可选便利功能-为您注入“this”+
//如果p_child_uu是私有的,则提供更好的封装
模板
void set_child(){
p_child_uu=std::使_唯一(此);
}
Child&Child(){return*p_Child}
};
结构子对象1:子对象{
使用Child::Child;
int f()常量重写{return 1;}
};
int main()
{
亲本p;
p、 p_child=std::make_unique(&p);//直接分配
Std::Cout?这里没有第一个头文件问题的循环引用吗?你是对的!但是这可能是用前向声明来固定的。我真的不明白。通过声明,子类知道它的父母。当创建子实例时,父类“填充”也被包含进来。考虑使用智能指针。(例如,unique_ptr或弱_ptr)。关于您的问题:在您的设计中使用智能指针肯定是更好的选择,但您需要注意所有权语义,以及弱引用(例如,父指针).Child的唯一指针很少能满足要求,因为您可能希望将它们与客户端应用程序共享,并跟踪这些引用。我的做法是依赖唯一所有权,直到证明需要共享为止。当然,这是一个很好的做法。我只是从此类构造的经验谈起,即你将以std::shared_ptr
作为正确的设计结束。Parent
应该可以有多个子s这一点我也弄错了吗?家长总是只有一个孩子。所有以前的孩子都可以删除。@Escualo这是我避免回答不清楚的问题的一个原因。孩子不应该被排除在外活在父对象中(在本例中)@JohnyP.太简单了-只需要呈现的代码。仅供参考/-有人讨论过在语言中添加std::nonowning_ptr
,这会使预期的语义比原始指针更明显,但现在原始指针应该只用于非所有权语义,如unique_ptr
,shared\ptr
,弱\u ptr
覆盖了99%的其他情况,如果您有一些定制需求,您可能应该编写您自己的智能指针来覆盖它。是什么阻止某人只做删除我的原始\u ptr;
并删除它背后的内存?@JohnyP.:封装;这是一个问题-p\u父对象将如果在客户端使用不可信的较大代码体中使用,通常会使其成为私有的。@JohnyP。类始终可以访问自己的私有成员,并提供父和父(){return*p_parent}
和常量parent&parent()常量{
#include <iostream>
#include <memory>
struct Parent;
struct Child {
virtual ~Child() { }
Child(Parent* p_parent) : p_parent_{p_parent} { }
virtual int f() const { return 0; }
Parent* p_parent_;
};
struct Parent
{
std::unique_ptr<Child> p_child_;
// optional convenience function - injects "this" for you +
// provides better encapsulation if p_child_ is made private
template <typename ChildT>
void set_child() {
p_child_ = std::make_unique<ChildT>(this);
}
Child& child() { return *p_child_; }
};
struct Child__1 : Child {
using Child::Child;
int f() const override { return 1; }
};
int main()
{
Parent p;
p.p_child_ = std::make_unique<Child>(&p); // direct assign
std::cout << p.child().f() << " should be 0\n";
p.p_child_ = std::make_unique<Child__1>(&p);
std::cout << p.child().f() << " should b1 1\n";
p.set_child<Child>(); // using convenience function...
std::cout << p.child().f() << " should be 0\n";
}