0

この質問をより明確にするために言い換えたいと思いました。私のアプローチは一般的に間違っていると感じています

新しい共有ポインターを作成してそれをベクトルにプッシュする目的で、共有ポインターのベクトルへの参照をコンストラクターに渡すという依存性注入の意図を破りますか?

新しいコマンドをオブジェクト内から使用するべきではないことを私は知っています。この例では、オブジェクトを作成しますが、外部に保存します。

「新しい」が外側にとどまることができるようにこれに近づくより良い方法はありますか?

SpottingMarker.h

#ifndef SPOTTINGMARKER_H_INCLUDE
#define SPOTTINGMARKER_H_INCLUDE


class SpottingMarker
{
public:
    SpottingMarker() {;}
            ~SpottingMarker(){;}
    void blah();

    double mPosition;
    double mDuration;
    char* mDescription;
};
    #endif

SpottingMarker.cpp

#include "SpottingMarker.h"
void blah() {;}

CsvSpottingNotes.h

#ifndef CSVSPOTTINGNOTES_H_INCLUDED
#define CSVSPOTTINGNOTES_H_INCLUDED


#include "SpottingMarker.h"
#include <boost/shared_ptr.hpp>
#include <vector>

typedef boost::shared_ptr<SpottingMarker> spottingMarker_ptr;

class CsvSpottingNotes
{
public:
    CsvSpottingNotes(const char* filename, std::vector<spottingMarker_ptr> &SpottingMarkerSet);
    ~CsvSpottingNotes(){;}
    const char* mFilename;
    const char field_terminator;
    const char line_terminator;
    const char enclosure_char;
};
    #endif

CsvSpottingNotes.cpp

#include "CsvSpottingNotes.h"
#include "SpottingMarker.h"
#include <csv_parser/csv_parser.hpp>
#include <boost/shared_ptr.hpp>

CsvSpottingNotes::CsvSpottingNotes(const char* filename, std::vector<spottingMarker_ptr> &SpottingMarkerSet) :
field_terminator(','),
line_terminator('\n'),
enclosure_char('"')

{
    spottingMarker_ptr aSpottingMarker(new SpottingMarker());
    SpottingMarkerSet.push_back(aSpottingMarker);
}

main.cpp

#include "CsvSpottingNotes.h"
#include "SpottingMarker.h"
#include <vector>

int main(int argc, char ** argv)
{
    typedef boost::shared_ptr<SpottingMarker> spottingMarker_ptr;
    const char* filename = "AT_92.csv";
    std::vector<spottingMarker_ptr> spottingMarkerSet;
    CsvSpottingNotes structure(filename, spottingMarkerSet);
}
4

1 に答える 1

1

まず、当面の質問に答えるために、私が正しく理解している場合は、(1)ローカルスコープで共有ポインターを作成し、(2)共有ポインターのベクトルへの参照の後ろにプッシュして、 (3)ポインタが作成時と同じオブジェクトを参照するようにします。これらすべてに対する答えは「はい」であり、その動作はほとんど無料で得られます。例えば:

void push_shared_pointer(std::vector<boost::shared_ptr<int> > &vector) {
  boost::shared_ptr<int> int_ptr(new int(5));
  vector.push_back(int_ptr);
  *int_ptr = 6;
}

std::vector<boost::shared_ptr<int> > int_vector;
push_shared_pointer(int_vector);

std::cout << *int_vector.back( ) << std::endl;

関数では、共有ポインターをベクトルにプッシュした後、ローカル共有ポインターを使用して参照されたintを変更したため、これは6を出力します。ベクター内の共有ポインターとローカル共有ポインターは同じメモリー位置を参照しているため、両方の共有ポインターが更新されます。

コードの残りの部分に関しては、注意すべきことがいくつかあります。まず、他の人が指摘したように、プリプロセッサガードが問題でした。次に、SopttingMarker.cppの関数blah()のスコープを設定して、SpottingMarkerクラスのblah関数の実装であることをコンパイルに通知しませんでした。それは読むべきです:

#include "SpottingMarker.h"

void SpottingMarker::blah() { }

さらに、ヘッダーでユーザー定義のデフォルトコンストラクターを提供することを示したので、SpottingMarker.cppでもそれを提供する必要があります。

SpottingMarker::SpottingMarker()
  : mPosition(0)
  , mDuration(0)
  , mDescription(NULL)
{ }

第3に、CsvSpottingNotes.hでデストラクタを宣言したので、CsvSpottingNotes.cppで定義する必要があります。

CsvSpottingNotes::~CsvSpottingNotes() {
  // implementation here
}

少なくともビルドログによれば、これらは必要なすべての定義である必要があります。

最後に注意するのは、3つの理由から、従来の方法で依存性注入を使用しているようには見えないということです。まず、通常、依存性注入を行う場合、注入されたオブジェクトへの参照をレシーバーオブジェクトに格納して、レシーバーがその存続期間にわたって使用できるようにします。ここでは、ベクターをCsvSpottingNotesに挿入しますが、そのベクターへの参照をクラスに格納しません。共有ポインタをその上にプッシュするだけです。

第二に、私の経験では、依存性注入は動作の抽象化、つまり、インターフェイスを使用して注入されたオブジェクトの動作からレシーバー(クライアント)オブジェクトの動作を分離するためのものです。これにより、インターフェイスのさまざまな実装を挿入することにより、クライアントの動作を変更できます。この場合、インターフェースを使用していません。std :: vectorはコンパイル時に完全修飾型であり、CsvSpaottingMarkerは他の型では使用できないため、依存性注入を使用する理由はありません。より良い解決策は、ベクトルをCsvSpottingMarkerのメンバーとして保存することです。

第3に、前述したように、依存性注入は主に動作の抽象化に使用されます。つまり、注入されるインターフェイスの実装に応じて、クライアントオブジェクトの動作が異なります。std :: vectorクラスは、動作を提供しないため、依存性注入の候補としては適していません。代わりに、状態を保存するだけです。通常、オブジェクトの状態は、オブジェクトクラスのメンバーとしてカプセル化する必要があります。これは、CsvSpottingMarkerクラスにベクトルを含めるためのサポートです。

お役に立てば幸いです。

于 2012-05-17T01:48:07.017 に答える