C++ C++;typedef与非人工继承
我有一个由嵌套STL容器构成的数据结构:C++ C++;typedef与非人工继承,c++,stl,C++,Stl,我有一个由嵌套STL容器构成的数据结构: typedef std::map<Solver::EnumValue, double> SmValueProb; typedef std::map<Solver::VariableReference, Solver::EnumValue> SmGuard; typedef std::map<SmGuard, SmValueProb> SmTransitions; typedef std::map<Solver::
typedef std::map<Solver::EnumValue, double> SmValueProb;
typedef std::map<Solver::VariableReference, Solver::EnumValue> SmGuard;
typedef std::map<SmGuard, SmValueProb> SmTransitions;
typedef std::map<Solver::EnumValue, SmTransitions> SmMachine;
typedef std::map SmValueProb;
typedef std::map SmGuard;
typedef std::map SmTransitions;
typedef std::map SmMachine;
这种形式的数据只在我的程序中短暂使用,除了简单地存储它们的数据之外,附加到这些类型的行为并没有什么意义。但是,编译器(VC++2010)抱怨生成的名称太长
将类型重新定义为STL容器的子类而无需进一步细化似乎是可行的:
typedef std::map<Solver::EnumValue, double> SmValueProb;
class SmGuard : public std::map<Solver::VariableReference, Solver::EnumValue> { };
class SmTransitions : public std::map<SmGuard, SmValueProb> { };
class SmMachine : public std::map<Solver::EnumValue, SmTransitions> { };
typedef std::map SmValueProb;
类SmGuard:public std::map{};
类SmTransitions:public std::map{};
类SmMachine:public std::map{};
认识到STL容器不打算用作基类,在这种情况下是否存在任何危险?是的,存在:
std::map<Solver::VariableReference, Solver::EnumValue>* x = new SmGuard;
delete x;
std::map*x=新SmGuard;
删除x;
导致未定义的行为。有一个危险:如果在指向没有
virtual
析构函数的基类的指针上调用delete
,则存在未定义的行为。否则,你就没事了
至少这是理论。实际上,在MSVC ABI或安腾ABI(gcc、Clang、icc,…)中,只有当派生类使用非平凡析构函数添加非静态属性时,才会在没有虚拟析构函数的基类上删除(-Wdelete non-virtual dtor
带有gcc和Clang,前提是该类具有虚拟方法)出现问题(例如astd::string
)
在你的特殊情况下,这似乎很好…但是
……您可能仍然想封装(使用组合)并公开有意义的(面向业务的)方法。它不仅比不安全,更容易理解,比<代码> > ->第二。查找(“x”)->开始()/代码>…/P> < P>这是C++与“基于继承的经典OOP”的争议点之一。 必须考虑两个方面:
- typedef是为同一类型引入另一个名称:
和std::map
实际上是完全相同的东西,可以互换使用SmValueProb
- 一个类引入了一种新的类型,它(原则上)与任何其他类型无关
他们都规定了一些“规则”,关于语言“特征”必须如何使用,因为C++是多范式的——非它的特征满足了范式的要求,让一些污秽打开。 如上所述,继承std::map不会产生纯OOP可替换类型,因为基指针上的删除将不知道如何销毁派生部分,因为析构函数在设计上不是虚拟的
但是-事实上-这只是一个特殊情况:而且pbase->find
不会调用您自己的最终被覆盖的find
方法,因为std::map::find
不是虚拟的(但这并不是未定义的:定义很好,很可能不是您想要的)
真正的问题是另一个:“经典OOP替换原则”在您的设计中是否重要?
换句话说,您是否要互换使用类及其基,函数只取std::map*
或std::map&
参数,假装这些函数调用std::map函数,从而调用您的方法
- 如果是的话,继承就不是办法。std::map中没有虚拟方法,因此运行时多态性将不起作用
- 如果没有,也就是说:您只是编写自己的类,重用std::map行为和接口,不打算交换它们的用法(特别是,您没有使用new和deletin分配自己的类,如果将delete应用于std::map指针),只提供一组以
或yourclass&
为参数的函数,这很好。它甚至可能比typedef更好,因为您的函数不能再与std::map一起使用,从而分离了功能yourclass*
class myclass: public std::map<something...>
{};
std::map<something...>* p = new myclass;
delete p;
class myclass:public std::map
{};
std::map*p=新的myclass;
删除p;
UB很像吗
class myclass
{
public:
std::map<something...> mp;
};
std::map<something...>* p = &((new myclass)->mp);
delete p;
class-myclass
{
公众:
std::map-mp;
};
std::map*p=&((新myclass)->mp);
删除p;
第二个样本具有相同的特征