静态成员继承和保护
Static members inheritance and protection
我确实有一个关于C++中静态成员继承和保护的问题。我希望我能足够清楚,因为写思维状态并不总是那么容易:)我正在为一个图形程序编写一个简单的(文本解析器),该程序正在加载具有自定义格式的文本文件,现在文本部分几乎完成了,现在我需要生成一些对象,用我从文件中加载的数据向它们提供数据。
我认为这个问题属于第一小时。C++,但我卡住了。例如,我从文本文件中只加载了两种类型的逻辑"节点",LAYER和PLINE,它们也有它们的属性,这两种属性可以是通用的,也不能是通用的。LAYER与PLINE和back的关系现在完全无关,困扰我的是如何连接和处理两者的属性:
假设我选择DataObj作为两者的基类。DataObj有一个名为"name"的成员,因为LAYER和PLINE都可以有一个名称。LAYER有一个仅对图层公用的属性,例如"锁定",而PLINE有一个只对样条线公用的属性。例如"颜色"。按照"学校的方式"做事,它看起来像:
/// i use const char* for everything to not complicate things ...
...
class DataObj {
...
const char* name;
...
}
...
class Layer : public DataObj {
...
const char* locked;
...
}
...
class Pline : public DataObj {
...
const char* color;
...
}
...
int main(){
Layer* l = new Layer();
l.name = "first layer";
l.locked = "false";
Pline* p = new Pline();
p.name = "wonderful line";
p.color = "0xFF3300";
}
...
现在,我想以一种更"动态"的方式来做这件事,我真的不在乎静态类型的成员名称(将来可能还会是访问器),尤其是在向对象提供来自解析器的数据时。我的意思是,只使用2种节点类型很容易做到这一点,但我会有几十种以上的节点类型。
因此,我想做的概念是"静态"推送每个节点类型(类)的允许属性向量,然后只检查对象中是否允许该属性,并在解析过程中设置它。我可能想要两个重要的成员1。是kv对的std::map,第二个是某个节点允许属性的静态向量。按照之前键入的代码:
...
class DataObj {
...
static std::vector<const char*> allowedAttrs;
std::map <const char*, const char*> attrs;
private:
static bool isInit;
...
}
...
DataObj::DataObj(){
if(!isInit)
allowedAttrs.push_back("name");
isInit = true;
}
...
Layer::Layer(){
if(!isInit) // private static for Layer
allowedAttrs.push_back("locked");
}
...
Pline::Pline(){
if(!isInit) // private static for Pline
allowedAttrs.push_back("color");
}
...
我在这里遇到的问题可能从月球上就能看到。如果我们初始化一个新的层,然后创建一个新Pline,Pline将在allowedAttrs向量中具有名称、锁定和颜色,这是不正确的,因为"锁定"应该只对层节点有效。
因此,我需要一些方法来解决这个问题,即成员"allowedAttrs"对于Layer对象中的"locked"等非公共属性变为"private",但同时保留其来自超类"DataObj"的"public"性质,这样它就可以捕获"name"等共享属性。换言之,我不想"破坏"一直到基类的"继承流",并为重复相同代码的每个节点类(对象)定义新的变量。(有点像虚拟变量)。
我希望这个问题不是(那么)愚蠢,我真的会感谢你的回答。
1)我会为每个类型使用单独的静态成员来保存每个类型允许的属性
2)将静态成员移动到函数中,这样更安全,并且可能避免检查它是否一直初始化(取决于编译器的性能和其他细节)
3)除了非常具体的事情之外,不要使用const char*
。如果您不知道这些东西是什么,请始终使用std::string
。在这种情况下,我们必须使用std::string
4)我将allowedAttrs
从向量更改为set
,这对于大量属性可能更快,对于较小的属性可能更慢。
这是基础:
class DataObj {
const std::set<std::string>& get_allowed_data_attributes() static {
static std::set<std::string> allowedAttrs = {"name"};
return allowedAttrs;
}
std::map <std::string, std::string> attrs;
public:
DataObj(){ }
void set_attribute(std::string key, std::string value) {
auto it = get_allowed_data_attributes().find(key);
if (it == get_allowed_data_attributes().end())
throw bad_key_exception(key);
attrs.insert(std::make_pair(std::move(key), std::move(value)));
}
const std::string& get_attribute(const std::string& key) const {
auto it = attrs().find(key);
if (it == attrs().end())
throw bad_key_exception(key);
return it->second;
}
};
这是衍生的:
class Layer : public DataObj {
const std::set<std::string>& get_allowed_data_attributes() static {
static std::set<std::string> allowedAttrs = {"locked"};
return allowedAttrs;
}
public:
DataObj(){ }
void set_attribute(std::string key, std::string value) {
auto it = get_allowed_data_attributes().find(key);
if (it == get_allowed_data_attributes().end())
DataObj::set_attribute(std::move(key), std::move(value));
else
attrs.insert(std::make_pair(std::move(key), std::move(value)));
}
const std::string& get_attribute(const std::string& key) const {
auto it = attrs().find(key);
if (it == attrs().end())
return DataObj::get_attribute(key);
else
return it->second;
}
};
请注意,如果您给它一个无效的密钥,它将抛出一个bad_key_exception
,您必须添加它。请确保它继承自std::runtime_error
。
以下是我将如何实现允许属性的向量。我会让每个类型都包含一个允许属性的列表,在初始化期间复制它们基类的列表。
class DataObj {
...
static std::vector<std::string> allowedAttrs;
std::map <std::string, std::string> attrs;
private:
static bool isInit;
...
}
class Layer {
static std::vector<std::string> allowedAttrs;
...
};
class PLine {
static std::vector<std::string> allowedAttrs;
}
...
DataObj::DataObj(){
if(!isInit)
allowedAttrs.push_back("name");
isInit = true;
}
...
Layer::Layer(){
if(!isInit) { // private static for Layer
allowedAttrs = DataObj::allowedAttrs;
allowedAttrs.push_back("locked");
}
}
...
Pline::Pline(){
if(!isInit) { // private static for Pline
allowedAttrs = DataObj::allowedAttrs;
allowedAttrs.push_back("color");
}
}
注:
对矢量和贴图都使用
std::string
,而不是char*
。虽然vector<char*>
可能很有用,但map<char*,char*>
只是一个bug。您可以通过使查找函数更智能一点来避免复制基类的列表。
- 为什么在保护模式下继承升级不起作用
- 继承和友元函数,从基类访问受保护的成员
- 所以我正在为我的学校作业练习继承,但我无法正确实施标题保护
- 为什么继承的受保护构造函数不能公开?
- 在使用受保护和继承时无法访问在类中声明的私有成员
- 继承期间受保护成员的皮条
- 在 lambda 函数 g++-4.8 中调用继承的受保护子类型
- 在派生类中具有相同签名但继承为受保护的函数
- 为什么我无法使用受保护/私有继承访问派生实例中基类的受保护成员?
- 使从一个基类派生的类能够使用继承的受保护成员
- 需要一些帮助了解私人 /保护 /公共继承
- 为什么继承的受保护操作员=()有公共访问权限
- C :可以从类及其受保护的成员类型继承可以继承吗?
- C++对已继承的受保护类成员的未定义引用
- 如何访问多个继承类中的受保护成员
- 用受保护的继承指向基类方法
- C 继承访问受保护的数据成员
- 在 std:: 容器中使用受保护继承的原因
- 具有多态性的多重受保护继承
- 带虚函数的受保护继承