2

マイクロコントローラーを扱う場合、本質的にグローバルなものがあります。シリアル ポートやその他のインターフェイスなどの周辺機器について考えています。また、グローバルであるだけでなく、コアクロックや割り込みコントローラーを制御する周辺機器のように、1 つしか存在しない (それ以上存在することはない) 周辺機器もあります。これらのペリフェラルにはある種のグローバル状態 (たとえば、コア クロックが何かに設定されている) があり、これらの値を逆算するのは非効率的です。

RTOS で使用されるシステム タイマーを設定する必要があり、他の周辺機器 (UART ボーレート、SPI ビットレートなど) のクロックを設定する必要があり、外部メモリに正しいクロックを設定するか、メモリ待機状態を構成する必要があります。そのため、main() で 1 つのオブジェクトを作成し、それをどこにでも渡すのは少し面倒だと思います...

すべての「グローバル」情報がペリフェラル レジスタから取得されるようにメソッドを作成することもできます (たとえば、現在の PLL 設定からコア周波数を逆計算することができます) が、これも間違った考えのように思えます。クロックジェネレーター周辺機器のどこでもおかしく見えるでしょう...

現在のクロック設定はクラスの静的メンバーに保存できますが、ここからは完全に静的なクラスに向けた小さなステップが 1 つだけあります (状態を持たないクラスでは「this」ポインターは役に立たないため)...

非オブジェクト指向プログラムで通常見られる解決策は、完全に静的なクラスに最も近いものです。グローバル変数を操作する関数のみがあります。

このようなシナリオを適切に処理する方法や、この問題に時間をかける価値があるかどうかについて、誰かが良い考えを持っていますか? たぶん、グローバル オブジェクトを 1 つだけ使用して、それで終了する必要がありますか? (;

4

4 に答える 4

5

プログラムをうまくオブジェクト指向にしたいのですが、そのようなオブジェクトをどのように扱うかを決めるのに苦労しています... グローバル変数は良くありません。これは明らかですが、わかりません (十分ではありません)。経験)これらがグローバルであるという事実を「隠す」ようにすべきかどうか...

私がそれを読んだとき、なぜ OOP を使用しているのか、なぜグローバルを使用していないのかを知っているのだろうかと思います。

まず、OOP はツールであり、目的ではありません。あなたの場合、割り込みコントローラーは派生や仮想関数などを必要としません。必要なのは、単一のクラスにラップされた、それをプログラムするためのインターフェースだけです。保守性を犠牲にすることなく、それを行う単純な関数のセット (C= スタイルのモジュラー プログラミング) を使用することもできます。あなたの場合、単一インスタンスをグローバルにすることはさらに明確です。プログラムのさまざまな部分が、同じ UART にアクセスするために使用されるクラスをインスタンス化できる別の方法を想像してみてください。グローバルを使用している場合、コード (または作成者) はこれを認識しており、アクセスを調整する方法を検討します。

ここで、グローバルに関して、それらを使用しない理由の例を次に示します。

int a, b, c;

void f1()
{
    c = a;
    f3();
}

void f2()
{
    c = b;
    f3();
}

void f3()
{
    // use c
}

int main()
{
    a = 4;
    f1();
    b = 5;
    f2();
}

ここでのポイントは、パラメーターが実際のパラメーターとして渡されるのではなく、グローバルに格納されているため、いつどこで使用されているかがわかりにくくなっているということです。また、上記の使用により、再帰呼び出しが完全に除外されます。ただし、環境に関しては、割り込みコントローラー (cin/cout/cerr/clog と同様) など、環境の固有の部分であるため、本質的にグローバルなものがあります。それらについて心配しないでください。アクセスを制限することを考える必要があるまで、本当に多くのそれらがいたるところで使用されている必要があります.

これを簡単にするためのガイドラインが 2 つあります。

  • オブジェクトのスコープが大きいほど、話す名前が必要になります (上記の a、b、c と比較してください)。あなたの場合、すべてのハードウェア固有のオブジェクトを共通の名前空間に格納するので、一部のコードがグローバルにアクセスしていることは明らかです。これにより、この名前空間を個別にテストして再利用することもできます。多くのハードウェア ベンダーは、アプリケーション開発を支援するために、このようなものをライブラリの形で提供しています。
  • ハードウェアをラップ/モデリングするコードでは、要求を実行しますが、その上にあるアプリケーションに固有の決定を下さないでください。たとえば、アサーションが失敗した後に中止する前に致命的なエラー情報をダンプすることを除いて、提供されているが標準ライブラリ自体によって使用されることのない標準ストリームと比較してください。
于 2013-04-07T08:32:36.337 に答える
2

オプションの概要をほぼ説明しました。

  • グローバル
  • クラス/シングルトンの静的データメンバー

最終的には、この 2 つのどちらかを決定し、美学またはその他の見通しからどちらが好きかを選択するのはあなた次第です。

結局のところ、あなたが言ったように、まだ1つのクロックジェネレーター、1つのUARTなどがあります.

心に留めておくべきことの 1 つは、抽象化のみを目的とした抽象化が多すぎると、どちらかと言えば、あまり得をしないということです。ただし、コードに不慣れな人がクラスのレイヤーの背後で実際にどのように機能するかを理解するのが難しくなる可能性があります。したがって、もしあれば、あなたのチームを考慮に入れてください。

于 2013-04-07T07:55:54.243 に答える
1

シングルトン、グローバル オブジェクト、静的クラス、それらはすべて同じです。邪悪なグローバル ステートを好きなソースでドレスアップしても、それは依然としてグローバル ステートです。問題は、いわばドレッシングではなく、サラダにあります。

少し調査されたパスは、Haskell スタイルのモナド コードです (C++ ではそうです)。自分で試したことはありませんが、見た目からすると、このオプションは楽しいはずです。たとえば、C++ での Monad インターフェイスの実装例については、こちらを参照してください。

于 2013-04-07T09:46:53.303 に答える