2016-03-04 92 views
7

我有一个类从std::string私下继承,并添加了一些功能。我希望能够像std::string一样使用这个类,所以我试图定义一个隐式转换运算符(operator string())。但是,我不断收到inaccessible base错误。私有继承和隐式转换

#include <iostream> 
#include <string> 

using namespace std; 
class Test:private string { 
    int _a; 
    public: 
    operator string() { 
     return "hello"; 
    } 
}; 

int main() { 
    Test t; 
    if(t == "hello") { 
     cout<<"world\n"; 
    } 
} 

错误:

trial.cpp: In function ‘int main()’: 
trial.cpp:15:13: error: ‘std::basic_string<char>’ is an inaccessible base of ‘Test’ 
if(t == "hello") { 
     ^

问题:

  1. 它是一个坏主意来定义这样的转换?这是否违反了推荐的编程习惯?
  2. 我该如何做这项工作?

编辑:锵更有益

trial.cpp:8:5: warning: conversion function converting 'Test' to its base class 'std::basic_string<char>' will never be used 
    operator string() { 
    ^
trial.cpp:15:8: error: cannot cast 'Test' to its private base class 'basic_string<char, std::char_traits<char>, std::allocator<char> >' 
    if(t == "hello") { 
    ^
trial.cpp:5:12: note: declared private here 
class Test:private string { 
     ^~~~~~~~~~~~~~ 
+0

请在将来发布完整的错误消息。 – AndyG

+0

“hello”不是std :: string。 –

+0

我想我可以使它工作的一种方式是使用公共继承,并使派生类“final”。我没有在派生类中分配任何额外内存,因此不会调用析构函数(?)不应该成为问题。 – SPMP

回答

4

转换功能。私有基类击败私有继承的目的。这是一部分原因,为什么标准禁止这种行为:

A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void .

如果你想访问基类,你应该继承公众。这可以让代码易读并且可以为其他可能需要维护的人员提供全面的代码。

+0

有一个不成文的规则,stl类不应该从派生,对吧?这是一个例外,那个规则可能被打破?正如我在其他评论中提到的,不要重写任何''std :: string''函数,我没有任何额外的内存分配,我可以让我的类“最终”。 – SPMP

+0

@ user2308211并不是说它们不应该从派生出来,而是大多数类(包括'std :: string')从来都不是以派生自它的意图而生成的。你可以从虚拟函数的缺乏(包括最重要的缺乏虚拟析构函数)中看到这一点。因此,如果您要将'std :: string *'删除到'Test'实例,则无论“Test”是否为“final”,您都会遇到未定义的行为。您应该考虑到这一点以及其他人在不知情的情况下使用'Test'的可能性。这是我投票反对这种继承的唯一主要原因。 – 0x499602D2

+0

@ 0x499602D2这主要是反对多态使用类的论据,或者更确切地说,是多态地存储它,而不是针对继承本身。这两个并不总是耦合。尽管如此,除了继承之外,为了增加功能,通常还有比继承更好的选择。 ** STL本身就是主要的习惯示例**:与Java Collection Framework等库不同,STL不使用继承,但功能更强大,因为算法可以更加自由地扩展功能。 好的答案,顺便说一下! – TheOperator

1
  1. Is it a bad idea to define such a conversion? Does this break any recommended programming practices?

是,继承,这不是为它设计一个类通常是一个坏主意。看起来你的问题(“添加一些函数”)的方法(“继承”)源自其他继承常用惯例的编程语言,例如Java。

在你有价值语义和强大的抽象机制的完整范围的C++中,继承往往会产生比解决问题更多的问题,因为某些函数可能不是虚拟的,为了多态存储对象,必须使用动态分配。

How can I make this work?

是否有一个理由,为什么你不使用标准C++方式 - 全局函数?它们有很多优点:可以在不改变类的情况下添加它们,也不会强制用户使用不同的类(您的派生类),并且通过限制成员函数的数量来增加封装(它可以直接访问类内部) 。

+0

这是私有继承。所以我不知道你为什么说继承是一个坏主意.. – SPMP

+0

我提到的观点一般适用于继承。你是否可以在你的初始文章中添加你想要实现的内容,即你想添加到'std :: string'中的哪些功能不能被另外添加? – TheOperator

+1

我需要的任何功能都可以使用简单的功能完成。但我不认为这是重点。 – SPMP

2

我知道有两种方法可以做到这一点,但仍然有效。这是不是真的隐含的,但...

越少可怕的方式是显式调用操作:

if(t.operator string() == "hello") 

更可怕的方式是C样式转换。

if (*(string*)&t == "hello") 

注意这个执行static_cast基类指针,而不是它的邪恶兄弟的reinterpret_cast

cppreference上显式转换:

pointer or reference to a derived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class is inaccessible

+0

让隐式的一种方法是使用公有继承,对吧?我不重写任何''std :: string''函数,我没有任何额外的内存分配,我可以让我的类“最终”,从而防止其他人继承。这是否有任何理由说明为什么公共遗产仍然不好? – SPMP

+0

@ user2308211不是我所知道的,但这并不意味着我没有意识到的原因。 –

+0

我保持答案不被接受的一点点,以防万一有人提出了一些事情。但是,谢谢你的回答 – SPMP