2016-04-27 1 views
1

ツリー内のすべてのクラスは、電圧と電流センサー(通常は1,2,3 ...という名前)を監視するための他のクラスとの関係に依存します。問題は、そこにあるセンサの数は、どのタイプのユニットがシミュレートされているかに依存します。派生クラスだけがそれを知っていることを意味します。クラス定義内に組み込みの配列を使用しますが、派生クラスに遅延されたサイズは隠蔽の原因になりますか?

#include <iostream> 
class A { 
public: 
    A() {}; 
    virtual void Display() = 0; 
protected: 
    int array[]; // size is purposefully left out in base class 
}; 

class B : public A { 
public: 
    B(int numbers[4]); 
    virtual void Display(); 
protected: 
    int array[4]; // 4 sensors are required, number fixed at compile time 
} 

B::B(int numbers[4]) { 
    for(int i=0; i<4; i++) 
      array[i] = numbers[i]; 
} 

void B::Display() { 
    cout << " B numbers are: "; 
    for(int i = 0; i < 4; i++) 
      cout << array[i] << " "; 
    cout << endl; 
} 

class C : public A { 
public: 
    C(int numbers[8]); 
    virtual void Display(); 
protected: 
    int array[8]; // 8 sensors needed, number fixed at compile time 
}; 

C::C(int numbers[8]) { 
    for(int i=0; i<8; i++) 
      array[i] = numbers[i]; 
} 

void C::Display() { 
    cout << " C numbers are: "; 
    for(int i = 0; i < 8; i++) 
      cout << array[i] << " "; 
    cout << endl; 
} 

このドライバは、G ++コンパイラを使用する場合、これは技術的に機能することを示しているが、私はBとCクラスの配列を再宣言することによって隠蔽データを有していてもよいことを恐れ。

main() { 
    int B_numbers[] = {1,2,,3,4}; 
    int C_numbers[] = {5,6,7,8,9,10,11,12}; 
    B b(B_numbers[]); 
    C c(C_numbers[]); 
    b.Display(); 
    c.Display(); 
} 

誰もが提供できるご提案ありがとうございます。

+1

メンバーデータをオーバーライドすることはできません(独立した配列を作成しています)。 'int array [];'はサイズがゼロの配列です。テンプレートを見る時間。 – LogicStuff

+0

あなたの最初の問題は、C++では長さがゼロの配列が許可されていないため、これは移植可能とは見なされないGCC拡張です。 –

+0

基本クラス 'virtual int * Array()'に仮想関数を追加することを検討してください。派生クラスはその配列へのポインタを返します。 – kfsone

答えて

1

表示されたコードの中には、A::arrayを使用していないため、不要なものとして削除することはできます。 BCはそれぞれDisplay()のそれぞれの上書きが何をするべきかを知っている独自の個人的な配列を持っています - Aはここに関与する必要はありません。ただ、持っている:B(int numbers[4]);が実際にB(int *numbers)から任意の違いはありません

struct A { 
    virtual void Display() = 0; 
}; 

。なお限りコンストラクタが行くと、そこにちょうど安全性の錯覚を与えている数は - 私は簡単に間違ったサイズの配列を渡すことができますそこ。そのため、std::arrayを使用することを好む - コピー構成可能であるという付加的な利点を有する:

class B : public A { 
public: 
    B (std::array<int, 4> const& arr) 
    : array(arr) 
    { } 

    virtual void Display(); 
protected: 
    std::array<int, 4> array; 
} 
1

関数は「仮想」にすることができます。つまり、呼び出された実際の関数は、オブジェクトのvtableでルックアップすることによって特定のオブジェクトに対して決定されます。これがオーバーロードの仕組みです。派生クラスのインスタンス化されたオブジェクトは、派生した関数を指すvtableを持ちます。

データメンバーのためにC++は行いません。派生クラスのデータメンバーは基本メンバーとは異なります。配列にアクセスしようとすると、オブジェクトを指す変数の型に基づいて選択されます。ではなく、オブジェクト自体の型です。そしてそのは良いことではありません

Cは足で自分を撃つのを容易にします。 C++では難しくなりますが、そうすると、足が痛くなります。 -Bjarne Stroustrupのよくある質問

+0

階層が明確になるのは、基本クラス、配列のサイズが分かっている中間クラス、そしてさまざまな仮想関数の構成に特有の調整を行う「リーフ」クラスの3つのレベルになります。 – Cam2025

0

あなたは派生クラスで使用できるベースクラスでアレイを提供するために、テンプレートアプローチを使用することから利益を得ることができますコンパイル時のサイズを定義します。このような

何か:

#include <array> 
#include <iostream> 

template<size_t N> 
class A 
{ 
public: 
    A(): arr{} {} 
    A(const std::array<int, N>& arr): arr{arr} {} 

    virtual ~A() = default; // needs virtual destructor 

    void Display() const // doesn't need to be virtual 
    { 
     for(auto n: arr) // generic code 
      std::cout << n << ' '; 
     std::cout << '\n'; 
    } 

    int Get(size_t n) const { return arr.at(n); } 
    void Set(size_t n, int value) { arr.at(n) = value; } 

protected: 
    std::array<int, N> arr; 
}; 

class B: public A<4> 
{ 
public: 
    B(const std::array<int, 4>& numbers): A(numbers) {} 
}; 

class C: public A<8> 
{ 
public: 
    C(const std::array<int, 8>& numbers): A(numbers) {} 
}; 

int main() 
{ 
    std::array<int, 4> B_numbers = {1, 2, 3, 4}; 

    B b(B_numbers); 
    C c({5, 6, 7, 8, 9, 10, 11, 12}); 

    b.Display(); 
    c.Display(); 
} 

出力:

1 2 3 4 
5 6 7 8 9 10 11 12 

このアプローチの利点は、唯一の性質に依存している基本クラスの一般的な機能を(書くことによってstd::arrayクラスのように、arr.size()イテレータ)、サイズだけが異なる類似のクラスを作成する時間を節約できます。

0

これについては、いくつかの方法があります。

array[]が基本クラスで保護されていると宣言した場合、すべての派生クラスにアクセスできることを意味します(再定義する必要はありません)。

データが常に意図どおりであることを確実にしたい場合は、追加のarray定義を削除して、あいまいさ(同じ名前の基本クラスと派生クラスメンバを持つ)を作成し、配列のサイズを保護された変数として指定します。この変数は、それぞれの派生クラスのコンストラクタで割り当てることができます。

あなたは次のように、これは、ベクターを用いだろうコーディングでき代替方法:

#include <iostream> 
#include <vector> 

using namespace std; 

class A { 
    public: 
     A() {}; 
     virtual void Display() = 0; 
    protected: 
     vector<int> array; 
     int size; 
}; 

class B : public A { 
    public: 
     B(int *numbers); 
     virtual void Display(); 
}; 

B::B(int *numbers) { 
    size=4; 
    for(int i=0; i<size; i++) 
     array.push_back(numbers[i]); 
} 

void B::Display() { 
    cout << " B numbers are: "; 
    for(int i = 0; i < size; i++) 
     cout << array[i] << " "; 
    cout << endl; 
} 

class C : public A { 
    public: 
     C(int *numbers); 
     virtual void Display(); 
}; 

C::C(int *numbers) { 
    size=8; 
    for(int i=0; i<size; i++) 
     array.push_back(numbers[i]); 
} 

void C::Display() { 
    cout << " C numbers are: "; 
    for(int i = 0; i < size; i++) 
     cout << array[i] << " "; 
    cout << endl; 
} 

int main() { 
    int B_numbers[] = {1,2,3,4}; 
    int C_numbers[] = {5,6,7,8,9,10,11,12}; 
    B b(B_numbers); 
    C c(C_numbers); 
    b.Display(); 
    c.Display(); 
    return 0; 
} 

あなただけのクラスごとに一つの場所(コンストラクタ)でサイズを宣言し、その唯一の可能なコンテナがあります。この方法あなたのオブジェクトにあなたのデータを保持することができます。また、メモリ管理について心配する必要もありません。

余分に移動したい場合は、ベクトル(およびイテレータ)をどこでも使用できます。これにより、入力のサイズが常にストレージのサイズと一致するようになります。

関連する問題