我有两个在项目中使用的类。一个班级Callback
负责从回调中保存信息。另一个类UserInfo
是向用户公开的信息。基本上,UserInfo
应该是一个非常薄的包装器,它读取Callback
数据并将其提供给用户,同时还提供一些额外的东西。
struct Callback {
int i;
float f;
};
struct UserInfo {
int i;
float f;
std::string thekicker;
void print();
UserInfo& operator=(const Callback&);
};
问题是,向Callback
添加成员需要在UserInfo
中进行相同的更改,以及更新operator=
和类似的从属成员函数。为了使它们自动保持同步,我想这样做:
struct Callback {
int i;
float f;
};
struct UserInfo : Callback{
std::string thekicker;
void print();
UserInfo& operator=(const Callback&);
};
现在UserInfo
保证拥有与Callback
相同的所有数据成员。事实上,踢球者是数据成员thekicker
。在Callback
中没有声明虚拟析构函数,我相信其他编码器希望它保持这种状态(他们强烈反对虚拟析构函数的性能损失)。但是,如果通过thekicker
销毁UserInfo
类型,Callback*
将会泄露。应该注意的是,UserInfo
并不打算通过Callback*
接口使用它,因此为什么这些类首先是分开的。另一方面,为了修改一个结构而不得不以相同的方式改变三个或更多个代码,感觉不够优雅且容易出错。
问题:有没有办法允许UserInfo
公开继承Callback
(用户必须能够访问所有相同的信息),但不允许分配{ {1}}具体是因为缺少虚拟析构函数而引用Callback
?我怀疑这是不可能的,因为它首先是继承的基本目的。我的第二个问题是,有没有办法通过其他方法使这两个类保持同步?我想让UserInfo
成为Callback
的成员而不是父类,但我想要使用UserInfo
代替user.i
来直接阅读数据成员。
我想我是在寻求不可能的事情,但我一直对stackoverflow答案的巫术感到惊讶,所以我想我只是想问一下是否真的有一个补救措施。
答案 0 :(得分:3)
您始终可以强制执行“无法通过基类指针删除”#39;通过在基类中保护析构函数(在某种程度上)提到的约束:
即
// Not deletable unless a derived class or friend is calling the dtor.
struct Callback {
int i;
float f;
protected:
~Callback() {}
};
// can delete objects of this type:
struct SimpleCallback : public Callback {};
struct UserInfo : public Callback {
std::string thekicker;
// ...
};
正如其他人所提到的,您可以删除赋值运算符。对于pre-c ++ 11,只需将该函数的未实现原型设为私有:
private:
UserInfo& operator=(const Callback&);
答案 1 :(得分:1)
struct UserInfo : Callback {
...
// assignment from Callback disallowed
UserInfo& operator=(const Callback&) = delete;
...
};
请注意,STL具有很多的继承而没有虚拟析构函数。该文档明确声明这些类不是用作基类。
一些例子是vector<&gt ;, set<&gt ;, map<> ....
另一种方法是考虑私有继承,同时提供一个访问器方法来显示回调(在这种情况下,您也可以使用更清晰的封装)。
答案 2 :(得分:0)
是的,您可以使用一些技巧来保持成员同步并自动更新operator=
。但它很丑陋,涉及宏和一种使用包含文件的不寻常方式。
CallBackMembers.h:
MEMBER(int, i)
MEMBER(float, f)
其他地方:
struct Callback {
#define MEMBER(TYPE,NAME) TYPE NAME;
#include "CallbackMembers.h"
#undef MEMBER
};
struct UserInfo {
#define MEMBER(TYPE,NAME) TYPE NAME;
#include "CallbackMembers.h"
#undef MEMBER
std::string thekicker;
void print(); // you can use the macro trick here too
UserInfo& operator=(const Callback& rhs)
{
#define MEMBER(TYPE,NAME) NAME = rhs.NAME;
#include "CallbackMembers.h"
#undef MEMBER
return *this;
}
};