2016-03-04 29 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. どのように私はこの作業を行うことができますか?

EDIT:クランはい、それのために設計されていないクラスを継承することは一般的に悪い考えです

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

私はそれを動作させることができると思う方法の1つは、公開継承を使用し、派生クラスを '' final''にすることです。私は派生クラスに割り当てられた追加メモリを持っていないので、呼び出されていないデストラクタは問題にならないはずです。 – SPMP

答えて

4

プライベート基本クラスへの変換機能はprivate継承の目的に反し。これは、標準の行動のこの種を禁止した理由の一部だ:

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''関数をオーバーライドしないでください。追加のメモリが割り当てられていないので、クラスを '' final''にすることができます。 – SPMP

+0

@ user2308211派生してはならないというわけではありません。クラスの大部分( 'std :: string'を含む)のほとんどは、派生する意図で作られたものではありません。仮想関数の欠如(最も重要なことに、仮想デストラクタの欠如を含む)からこれを見ることができます。だから 'std :: string *'を 'Test'インスタンスに削除すると、' Test'が 'final'であってもいなくても、未定義の動作をします。あなたはそれを知っていなくても 'Test'を使って他の人々の可能性とそれを考慮する必要があります。これが私がこのような相続に反対する唯一の主な理由です。 – 0x499602D2

+0

@ 0x499602D2これは主に、ポリモフィックにクラスを使用したり、ポリモーフィックに格納したりすることを主張しますが、継承自体には反対しません。 2つは常に結合されていません。それでも、機能性を追加するために、継承よりも優れた選択肢があります。 ** STLは、Javaコレクションフレームワークのようなライブラリとは対照的に、継承を使用していませんが、アルゴリズムによって機能をさらに自由に拡張できるため、より強力です。 ところで、良い答えです! – 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++ウェイグローバル機能を使用しない理由はありますか?彼らはクラスを変更せずに、別のクラスを使用するユーザーを強制することなく追加することができます(あなたの1を得た)、彼らは(クラスの内部に直接アクセスすることができます)メンバ関数の数を制限することにより、カプセル化を増やす:彼らは多くの利点を持っています。

+0

これはプライベート継承です。だから私はあなたがなぜ継承するのは悪い考えだと言うのか分からない。 – SPMP

+0

私が言及したポイントは一般的に継承に当てはまる。初心者の投稿に正確に達成したいものを追加できますか?そうでなければ追加できない 'std :: string'にどのような機能を追加したいのですか? – TheOperator

+1

私が必要としていた機能は、シンプルな機能を使って実現できました。しかし、私はそれがポイントだとは思わない。 – SPMP

2

私は吸うこと、それを行うには知っているが、まだ動作は二つの方法があります。

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

もっとひどいの方法は、Cスタイルのキャストである:それは

あまりひどいの方法は、明示的にオペレータを呼び出している...しかし、実際には暗黙的ではありません。

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

このreinterpret_cast兄弟基本クラスのポインタではなく、その悪にstatic_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

それを暗黙的にする1つの方法は、公開の継承を使用することでしょうか?私は '' std :: string''関数をオーバーライドしません。追加のメモリが割り当てられていないので、他のクラスが継承しないように '' final''クラスを作ることができます。それは公的継承が依然として悪い理由を残していますか? – SPMP

+0

@ user2308211私が気づいているわけではありませんが、それは私が気づいていない理由があるという意味ではありません。 –

+0

誰かが何かを思いついた場合に備えて、私はちょっと答えを受け入れていません。しかし、回答ありがとう – SPMP

関連する問題