2017-10-24 18 views
0

私のコードを単純化するために、いくつかのオブジェクトを格納できる配列を使いたいと思っています。そのあとでそれらのオブジェクトの関数を呼び出すことができます。多くの異なるクラスで同じ関数を呼び出す

私は、(部分的に)同じメンバ関数でいくつかのクラスを作成しました。もちろん、これらの関数は異なる実装を持っています。これらのオブジェクトを単一の配列に配置したいと考えています。そのあと、それらの関数を呼び出すことができます。

私が持っているのは、いくつかのセンサーです。それらをSensor1、Sensor2、Sensor3と呼ぶことにしましょう。それらのすべてにreadSensor()という名前の関数とsensorData()という関数があります。 (実際のソフトウェアには10-12センサーと4つの機能があるので、コードを簡略化してセンサを簡単に追加できるようにしたいと思っています)。

だから、私は何を探していることは、このようなものです:私はそれらのすべてを書くことと、私はすべてのダウンを忘れてはいけないことを望んずに、すべてのセンサーを読むことができますこの方法

Sensor1 sensor1; 
Sensor2 sensor2; 
Sensor3 sensor3; 
byte nSensors = 3; 

(type?) *sensorList[nSensors] // list of pointers to the sensors - don't know how to declare this. 

void setup() { // yes, this is for Arduino. 
    sensorList[0] = &sensor1; // store the pointers to the class objects. 
    sensorList[1] = &sensor2; 
    sensorList[2] = &sensor3; 
} 

void readSensors() { 
    for (int i=1, i<nSnesors, i++) { 
    sensorList[i]->readSensor(); 
    } 
} 

この線。コードをもっと短くして、センサーを1か所に追加することができます。この配列は、すべてのセンサーが持つ機能(同じ実装でも同じ名前ですが、これはまったく異なるセンサーです)にのみ使用されます。オブジェクトにはセンサ固有の機能もあり、必要に応じて直接呼び出すことができます。

これも可能でしょうか?もしそうなら、どうですか?

+1

センサインタフェース(基本クラス)は多分? – alain

答えて

1

あなたは、単に仕事のランタイムポリモーフィズムを使用することができます。

例:

class SensorBase 
{ 
    public: 
    virtual void readSensor() = 0; 
    virtual void getData(char*) = 0; 
}; 

class Sensor1: public SensorBase 
{ 
    void readSensor() { std::cout << "read for Sensor1 called" << std::endl; } 
    void getData(char* ptr) { std::cout << "get for Sensor1 called" << std::endl; } 
}; 

class Sensor2: public SensorBase 
{ 
    void readSensor() { std::cout << "read for Sensor2 called" << std::endl; } 
    void getData(char* ptr) { std::cout << "get for Sensor2 called" << std::endl; } 
}; 

// Static allocate objects, new is not a good idea for small embedded devices 
// cause of significant overhead. Global objects are typically a design problem, 
// but small embedded systems have different requirements ;) 

Sensor1 sensor1; 
Sensor2 sensor2; 

// lets have array to objects, statically allocated 
SensorBase* arr[] = { &sensor1, &sensor2 }; 


int main() 
{ 
    char htmlString[256]; 

    for (auto ptr: arr) 
    { 
     ptr->readSensor(); 
     ptr->getData(htmlString); 
    } 
} 

あなたは、あなたのニーズに例の機能の内容を削除する必要があります。 std :: coutは、アプリがどのように動作するかの例として可視出力で実行できるようにするためにのみここで使用されています。

コードでsetupメソッドを使用します。それはおそらく大きなシステムでは良い考えですが、avrではありません!私の例のように静的割り当てを使用すると、あなたのコードは小さくて速くなります。コンパイラにいくつかのヒントを与えて、データフィールドやクラスのいくつかをフラッシュに保存すると、速度を上げることができます。そのトピックのために考慮してください#include <avr/pgmspace.h>

場合によっては、constexprコンストラクタでクラスを書く必要がありますフラッシュにデータを格納します。仮想メソッドを使って注意を払う必要があります:gccはそれらをフラッシュに保存できません。これは非常に古いバグ/設計上の問題で、小さなデバイスの多くのRAMを無駄にします。アームデバイスに切り替える1つの理由! https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43745を参照してください。あなたのコードに多相クラスがたくさん必要な場合、avr gccは使用できなくなります。このバグは修正されません!

+0

setup()とloop()は、私が使用するArduino IDEのデフォルトの方法です。コードはESP8266上で実行されるので、サイズはあまり問題にはなりません。この解決策は、私が必要とするように見えます。何が起きているのかを理解しようとします(これは実際にはライブラリクラスでもう少し複雑になります)。早速のお返事ありがとうございます! – Wouter

+0

@Wouter:アレイのどこかで定義され、setupメソッド内の値を埋めると、フラッシュとラムの使用量が増えます。だから、私は小さな組み込みシステムが完全に静的なグローバル定義を使うことを好みます。メインの開始前にすべてのデータがコピーされ、追加のコードを書き込まなくてはなりません。これはarduinoとは関係ありませんが、変数のデータがいつ、どのように有効になるかは、 Cライブラリの起動コードは、必要なコードをすでに提供しています。私の例に示すように、独自のコピーコードを書く必要はありません。 – Klaus

+0

実装済み - 完全に動作します、ありがとう!このプロセスで私のコードから約10〜20kBを削ってしまったようですが、それは良いことですが、私は余裕があります。私は約370kBにあり、500kBを少し上回ってうれしく思います。 OTAの更新はこれ以上できません)。 – Wouter

1

はいこれはPolymorphismを使用すると可能です。

あなたは、このメソッドを実装する基底クラス(すなわちSensor)と子クラスSensorはメソッドreadSensor()を宣言し(すなわちSensor1Sensor2Sensor3)、および3つのクラスのすべてを定義することができますが、彼らはでこれを行うことができます違う方法。そうすれば、型がSensorの配列を作成し、このメソッドを各要素で呼び出すことができます。次に、各要素が子クラスの実装されたメソッドを呼び出します。

FYI:必要に応じて、基本的な動作のために、子クラスのメソッドから基本クラスのメソッドを呼び出すこともできます。

たぶん同様に、このリンクをチェックしてください。tutorial

関連する問題