我有一个简单的类,它包含void
指针和int
(这是某种boost::Variant
教育项目。)
我还有一个工作副本构造函数和析构函数。
但是我的研究结果是,我将如何完成这样的事情:
Container cont1("some value"); //simple construction
Container cont2;
cont2.createLink(cont1); //this should initialize members with a reference (or something alike)
std::cout<<cont1; //yields "some value"
cont2.set(20); //setting this container should update the original container too, since I initialized with a reference (or smth alike)
std::cout<<cont1; //yields 20
这是该类的简化版本:
class Container {
public:
Container(){}
Container(const std::string &val){var.type = STRING; var.data = new std::string(val);}
Container(int val){ /* same for int */}
Container(const Container &val){ /* do a memory copy */}
void set(int val){ /* set the value if type matches, otherwise allocate a new pointer */}
void set(const std::string &val){ /* the same as for int */}
void createLink(const Container &val){ /* somehow assign a reference or whatsoever */}
private:
typedef struct VAR {
int type = 0;
void *data = NULL; }
VAR var;
}
如果我将cont2
的值设置为string
(即此刻它保持的数据类型相同),一切都很好,因为该集合不会分配新的指针而是分配一个新的价值
但是,如果我为cont1
分配不同的值并因此必须分配新指针,如何确保cont2
的指针更新?
我需要像shared_pointer
这样的东西吗?
感谢您的任何见解!
修改
我改为功能名称,以便更清楚地说明应该发生什么。
答案 0 :(得分:1)
有一种解决方案只涉及直接OO。您可以为变量类型创建一个接口,并使用double间接到变量实例,以允许链接的容器共享相同的变体实例。
需要双重间接的原因是,如果新类型与原始类型不匹配,您希望set()
方法自动分配新变体实例的方式。如果我们只是从两个容器共享一个指向变量的指针,那么在set()
创建一个新的变量实例之后,每个容器将再次引用不同的实例。
为了解决这个问题,我们可以使用指针指向容器中变体的指针。
以下是定义变体界面的可能方法,以及如何将其子类化:
typedef std::ostream Out;
struct BadType {};
struct Var {
virtual ~Var () = default;
virtual Out & print (Out &os) { return os << "(BadType)"; }
virtual void set (int) { throw BadType(); }
virtual void set (const std::string &) { throw BadType(); }
};
struct VarInteger : Var {
int data;
VarInteger (int v) : data(v) {}
Out & print (Out &os) { return os << data; }
void set (int v) throw() { data = v; }
};
struct VarString : Var {
std::string data;
VarString (const std::string &v) : data(v) {}
Out & print (Out &os) { return os << data; }
void set (const std::string &v) throw() { data = v; }
};
以下是如何定义指向指针的方法,以及如何初始化指针:
typedef std::shared_ptr<Var> VarPtr;
std::shared_ptr<VarPtr> varptr_;
static VarPtr make_var () { return std::make_shared<Var>(); }
static VarPtr make_var (int v) { return std::make_shared<VarInteger>(v); }
static VarPtr make_var (const std::string &v) {
return std::make_shared<VarString>(v);
}
VarPtr & var () { return *varptr_; }
const VarPtr & var () const { return *varptr_; }
Container () : varptr_(std::make_shared<VarPtr>(make_var())) {}
Container (int v) : varptr_(std::make_shared<VarPtr>(make_var(v))) {}
Container (const std::string &v)
: varptr_(std::make_shared<VarPtr>(make_var(v))) {}
以下是您的set()
方法和createLink()
方法的实施方式。
void set (int v) {
try { var()->set(v); }
catch (BadType) { var() = make_var(v); }
}
void set (const std::string &v) {
try { var()->set(v); }
catch (BadType) { var() = make_var(v); }
}
void createLink (const Container &val) { varptr_ = val.varptr_; }
答案 1 :(得分:0)
以下内容如何?当然createLink
不能不接受const引用,所以我把它作为一个非const指针。
class Container {
const int STRING = 0x0000001;
const int INT = 0x0000002;
const int LINK = 0x8000000;
public:
...
void set(int val){...}
void set(const std::string &val)
{
if (var.type == LINK)
{
reinterpret_cast<Container*>(var.data)->set(val);
}
else
...
}
void createLink(Container* val)
{
var.data = val;
var.type = LINK;
}
private:
typedef struct VAR {
int type = 0;
void *data = NULL;
};
VAR var;
};
要考虑一些重要的观点 - 链接的相对生命周期和链接是最明显的。