2012-04-20 15 views
1

クラスの作成に関しては、パブリックデータメンバーはいません。それは問題ありませんが、私は理由を理解していますが、ここに私の問題があります。私はクラスで使用している構造体を持っている(リニアリンクリスト)。私は実際に構造体フィールド(配列)の1つをNULLに初期化して、クライアントが有効な構造体を渡していることを確認できるようにしたいと思います。私はC++が構造体宣言のデフォルト値を設定させないことを理解しています。どうすれば私のゴミをクライアントから守ることができますか?構造体またはクラスとパブリックデータはどうですか?

struct task { 
    char *description; 
    char *name; 
    float time_remaining; 
    float time_spent; 
}; 

その後、私のクラスで私のような何かをしようとしている:何...

//I am making a copy of "to_add" and storing it in the LLL 
int list::add_to_list(const task & to_add) 
{ /.../ } 

私は、ユーザーがリンクリストに初期化されていない「タスクの」の束を追加する必要はありませんが何をする?その構造体をクラスに変換してデータメンバーをプライベートに移動させると、データメンバーにアクセスしてそれらのコピーを作成しようとする問題が多かったです。私はvarの価値をもたらすために何もしないように非常に注意を払っていましたが、コンパイラから離れて "エラー:" const taskを 'this'の引数 'char * task :: get_comp_name' ()は修飾子を捨てる[-fpermissive] "(" get_comp_name ")は私がコピーを渡すだけで値を編集していないと確信していたゲッターの1つでした)顔に(表情に。

+0

私は理解できません問題。パブリックデータメンバーは、「外部」の世界にとって「興味深い」データにアクセスする唯一の方法は、ゲッターによるものであり、設定が必要な場合は、セッターを経由しなければなりません。インスタンスが作成されると、プライベートメンバーを任意のものに初期化できます。メソッドの引数として外部から渡されたものは、安全ではない可能性がありますが、これは「正常」です。パブリックデータが必要でない場合は、2つの異なる「事実」と思われます。もっと説明できますか? – ShinTakezou

+0

エラーは、関数 'const'を宣言しなかったためです。公共のデータではなくアクセサーを提供したいなら、getterは 'char const * get_comp_name()const;'のようなものでなければなりません。 –

答えて

4

C++では、structclassはアクセス制御を除いて同じです。したがって、構造体のメンバーと継承へのデフォルトのアクセスはpublicですが、クラスのprivateはprivateです。したがって、構造体にデフルトコンストラクタなどを与えて初期化することができます。

struct task { 
    task() : desctiption(0), name(0), time_remaining(0.), time_spent(0.) {} 
    char *description; 
    char *name; 
    float time_remaining; 
    float time_spent; 
}; 

コンストラクタを追加の一副作用は、構造体がもはや凝集しないということです。これはあなたにとって問題かもしれません。 C++ 11では

、あなたはまた、宣言の時点でメンバーを初期化することができます:

struct task { 
    char *description{nullptr}; 
    char *name{nullptr}; 
    float time_remaining{0}; 
    float time_spent{0}; 
}; 

このインプレース初期化があまりにもtype x = y構文を受け入れ、値の引数レス{}初期結果の初期化では、のプリミティブ型の初期化はであるため、この例の引数を省略することができます。

+0

+1。ところで、 'char * name {}'で十分です。同様に、 'float time_spent {}'。 [詳細はこちら](http://stackoverflow.com/questions/10147264/braces-around-string-literal-in-char-array-declaration-valid-e-g-char-s/10147335#10147335)。 – Nawaz

+0

@Nawaz確かに、私は何かを追加します。 – juanchopanza

+0

それはそれです!私は皆さんが大好きです。ここには多くの賢い人がいます。ありがとう、トン! – MCP

1

構造体のコンストラクタを実装します。

struct task { 
    task() : description(0), name(0), time_remaining(0), time_spent(0) {} 
    char *description; 
    char *name; 
    float time_remaining; 
    float time_spent; 
}; 

C++でクラスと構造体の唯一の違いは、それのメ​​ンバーのデフォルトアクセシビリティです。

+0

他の相違点は、デフォルトの継承です。これは、構造体の場合はpublic、クラスの場合はprivateです。 – juanchopanza

+0

@アンドレアス:C++の* visibility *と* accessibility *には違いがあります。あなたが書かなければならないのは、*アクセシビリティ*、** ** *可視性*ではありません。 – Nawaz

2

ここにいくつかの問題があります。

パブリックまたはパブリックではありませんか?

パブリック属性は便利なように見えるかもしれませんが、ほとんどの場合、あなたが少なくともそれを期待しているときにあなたを噛ませるように戻ってきます。私はすでにtime_remainingtime_spentの問題を疑っています。どちらも同じ時刻にかなり修正されていると思いますが、そうではありませんか?クラスは、time_remaining + time_spentとして不変を強制できるようにデフォルトで

、可変属性は、privateなければならないタスクの寿命を通して一定です。

定数属性がpublicであれば問題ありませんが、インバリアントでの役割はコンストラクタ内で一度だけ決まります。

しかし、奇妙なエラーメッセージ?

これは良いチュートリアルや書籍がないためです。手元の問題は非常に単純です:constの問題です。

constオブジェクトは、const-referenceまたはvalueによって関数/メソッドに渡され、constメソッドだけが呼び出されます。あなたの場合、name()メソッドの適切な宣言は、メソッド名の後に修飾子constを持つ必要があります。

完全

それを入れて、それはそんなに簡単操作することですので、std::stringに投げます。

class Task { 
public: 
    Task(): time_remaining(0), time_spent(0) {} 
    Task(std::string name, std::string desc, float duration): 
     _name(name), _desc(desc), _time_remaining(duration), _time_spent(0) {} 

    // Accessors 
    std::string const& name() const { return _name; } 
    std::string const& description() const { return _desc; } 
    float time_remaining() const { return _time_remaining; } 
    float time_spent() const { return _time_spent; } 

    // Modifiers 
    void spend(float duration) { 
     _time_remaining -= duration; 
     _time_spent += duration; 
    } 

private: 
    std::string _name, _desc; 
    float _time_remaining, _time_spent; 
}; // class Task 

注:おそらくspendメソッドに渡されたdurationがそうでなければ、あなたが持っているよりも多くを費やし、_time_remaining属性に優れていないことを確認するために有益であり得る...

+0

それは素晴らしい宣言のように見えます!だからポイントに。アクセサーが行く限り:あなたは文字列を扱っているので、アクセサーはコピーを返すだけなのでしょうか?あなたが配列(すなわちポインタ)を使って作業しているならどうでしょうか?その関数名の後ろにある "const"は、配列の独立したコピーをアクセス/作成させるのに十分であろうか? – MCP

+1

@MCP:そうでない場合、文字列のconst参照である 'std :: string const&'を返しています。 'std :: string const name = t.name();'を書くと、 'std :: string const name = t.name();' ')は' const'値を取得します(後者の場合、 'const'はオプションではありません)。メソッドの 'const'は、クラスの内部属性を変更できないことを意味します。クラスがポインタを保持している場合、ポインタ自体は変更することはできませんが、 'const'で修飾されていない場合はポインタが指すオブジェクトを変更することができます。 –

+0

@MCP: 'const' -nessを理解するために、このサイトまたはチュートリアルで質問を探してください。適切に説明されていれば簡単な話題ですが、そうでない場合は全く混乱する可能性があります。特に技術的なものではなく、論理的な 'const' -nessのために使用することもできます。概念的な経験が必要です。 –

関連する問題