2016-03-04 98 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