是否允许从std命名空间中的类继承(即std :: wstring)?

时间:2009-12-06 21:19:47

标签: c++ gcc stl g++

类std :: wstring缺少“普通”c字符串(和文字)的一些操作。

我想在我自己的自定义类中添加这些缺少的操作:

#include <string>

class CustomWString : public std::wstring {

        public:

            CustomWString(const char*);
            const char* c_str(void);
};

上面的代码使用g ++ v4.4.1在Ubuntu Karmic上编译得很好。

但我想知道是否有反对这样做的论据?

编辑:一些例子来澄清“缺少操作”的含义:

std::wstring foo("hello"); // requires the L() macro or something like that
std::string bar("hello");
std::wstring goose(bar.c_str());

foo="hello";  // requires the L() macro
foo=bar.c_str();
foo=bar;

编辑:我想以某种方式“集中”。那是因为我有一个项目要从M $ -Windows移植,其中有数千个这些失败的操作。

好处是:有一个中心位置可以定义要使用的字符串类型,例如:

#ifdef WINDOWS_OS
    typedef std::wstring AppStringClass;
#else
    typedef std::string AppStringClass;
#endif

8 个答案:

答案 0 :(得分:15)

这是合法的,但很多人认为这是不可取的。问题是标准库模板类没有虚拟析构函数。所以如果你编写这样的代码:

std::wstring * p = new CustomWString ;
...
delete p;

你有未定义的行为。

答案 1 :(得分:10)

编译器绝对允许你,因为没有办法用C ++中的公共构造函数来密封类。

STL容器不是为继承而设计的,所以这通常是一个坏主意。 C ++必须忽略许多奇怪的角落。您的派生类可能会破坏另一个STL实现,或者只是更新构建环境。

但是,我认为这是一个严厉的警示标志,而不是完全禁止。这是“你真的很确定你在做什么,你知道所有的影响,并且对所有选择有充分的理由”吗?

在您的情况下:提供额外的构造函数很好(因为公共接口已记录在案,您可以复制它),并且只要您不引入新数据成员或VMT,切片或非虚析构函数不是问题。 (请记住,在通过没有虚拟DTor的基类指针进行删除时,C ++标准声明了未定义的行为)

然而我不确定如何在不提供字符串存储的情况下实现char const * c_str()。一旦你引入了新的数据成员,你就进入了一个地雷领域。

答案 2 :(得分:3)

我想你知道basic_string没有定义虚拟析构函数。以多态方式使用wstring是错误的。否则,您可以照常使用自定义类。

所以,以下是危险的:

vector<wstring*> mystrings;
mystrings.push_back(new CustomWString);
...
delete mystrings[0]; // No virtual destructor

直接使用您的自定义类就可以了,例如

vector<CustomWString> mystrings; // OK
mystrings.push_back("...");

答案 3 :(得分:3)

反对继承STL对象的传统观点是它们没有虚拟析构函数。所以,以矢量为例。如果我要继承它:

  class CMyVect : public std::vector<int>
  {
      ...
     int* someMemory;
  public:
     CMyVect()
     {
        someMemory = new int();
     }

     ~CMyVect()
     {
        delete someMemory;
     }
  };

基类中的非虚拟析构函数意味着如果用户指向CMyVect的ponter-to-vector-ints然后删除该指针,则不会调用析构函数,从而泄漏内存。也就是说:

 int main()
 {
     std::vector<int>* vecPtr = new CMyVect();
     delete vecPtr; // invokes vector constructor only, not yours
 }

所以这并不是说你不能继承这些对象,但它可以解决这个问题。你必须小心如何使用你继承的对象,或者你不需要你的析构函数来解雇(不要保留任何需要释放的资源)。

答案 4 :(得分:3)

这是可能的,合法的。但这是一个坏主意。这些类不是为继承而设计的,扩展它们最好不需要继承。如果您在使用类时不小心,您将获得未定义的行为。 (这些类没有虚拟析构函数)

此外,添加这些特定功能似乎是一个坏主意,因为它们依赖于语言环境和编码。你给了全班不止一个人的责任。在charwchar_t之间进行转换的功能属于其他地方。

答案 5 :(得分:2)

类模板std::basic_string(其中std::wstring是具有特定模板参数的typedef)具有虚拟析构函数,因此,公开继承它是一个坏主意

答案 6 :(得分:1)

你可以做到。但我认为没有意义,因为std :: basic_string (及其具体版本std :: string和std :: wstring) 定义没有虚拟方法并具有非虚拟析构函数。 所以没有办法,你可以正确使用你的子类代替例如的std :: wstring的。

答案 7 :(得分:0)

从一个类“继承”一个类的能力是一种语言特征。它只是一种正式,简单和干燥的语言功能,不依赖于任何特定的应用程序或任何特定的使用模型。它是一种低级工具,可用于不同目的。而且,为了回答你的问题,继承std::wstring类是完全合法的。

但是,接下来的问题是“为什么”这个问题。为什么要继承std::wstring

如果您在OOP范例中设计代码,那么从std::wstring继承公开可能不是一个好主意,“可能”在这里成为一个关键词。 OOP中的公共继承通常意味着多态类层次结构中的IS-A关系。类std::wstring并不是多态的,这就是为什么公开继承它可能会被视为一件非常奇怪的事情。

如果您在不同的范例中设计代码,例如模板元编程(TMP),那么公共继承可能是完全有效的事情。你看,在TMP中,公共继承服务于一个完全不同的目的,甚至与多态性和关系无关。

换句话说,如果不考虑大局,就无法对问题做出具体的回答。在任何情况下,要注意“机械”答案,例如“因为std::wstring没有虚拟析构函数,你不能继承它,因为它会破坏&lt;继续说明代码&gt; ”。即使在OOP方法中,这种推理也完全是假的。