16

さて、私のメインで私は持っています:

void somefunction();
int main()
{
    //bla bla bla
    SomeClass myclass = SomeClass();
    void(*pointerfunc)() = somefunction;
    myclass.addThingy(pointerfunc);

    //then later i do
    myclass.actionWithDiffrentOutcomes();
}

void somefunction()
{
    //some code
}

とクラスで:

class SomeClass()
{
    public:
        void addThingy(void (*function)());
        void actionWithDiffrentOutcomes();
    private:
        std::vector<void (**)()> vectoroffunctions;
}
SomeClass::addThingy(void (*function)())
{
    vectoroffunctions.push_back(&function);
}
SomeClass::actionWithDiffrentOutcomes()
{
    (*vectoroffunctions[0])();;
}

私はポインターに少し慣れていませんが、c ++の本、googled、extを読みました。これは正しいように見え、コンパイル、実行されますが、「actionWithDiffrentOutcomes()」を呼び出すと、アクセス違反が発生します。どうしたらいいかわかりません。正しいように見えますが、明らかに何かが間違っています。では、定義が別のクラスにある場合、クラス内から関数を呼び出すにはどうすればよいですか?

すべてのオプションをswitchステートメントにハードコーディングできないため、このようにしています。

4

3 に答える 3

20

あなたのコードはほぼ正しいです。ベクトルは、単に関数へのポインターではなく、関数へのポインターへのポインターを誤って保持しています。にポインタaddThingyのアドレスを追加していますが、そのポインタは次の行のスコープ外になります。functionvector

次のようにコードを変更します。

//Store pointers to functions, rather than
//pointers to pointers to functions
std::vector<void (*)()> vectoroffunctions;

SomeClass::addThingy(void (*function)())
{
    //Don't take the address of the address:
    vectoroffunctions.push_back(function);
}

また、コードの残りの部分に多くの構文エラーがあり、コードのコンパイルさえも停止するはずです。

于 2013-02-28T05:59:34.673 に答える
12

問題はここにあります:

vectoroffunctions.push_back(&function);

ローカル変数のアドレスを追加しています。関数から戻ると、ローカル変数は破棄されます。ベクターが保存するアドレスは、破壊されたオブジェクトを指しているため、実行時に「アクセス違反」エラーが発生します。

これを修正するには、次のようにします。

最初にこれを変更します

std::vector<void (**)()> vectoroffunctions;

これに:

std::vector<void (*)()> _functions; //vector of function-pointer-type
                                    //I changed the name also!

これは実質的に次のものと同じです。

std::vector<void()> _functions; //vector of function-type

今これを行います:

_functions.push_back(function); //add copy! 

より柔軟にするために、次のようにテンプレートを使用できますstd::function

class A
{
    public:
        template<typename Function>
        void add(Function && fn) 
        {  
            _functions.push_back(std::forward<Function>(fn)); 
        }
        void invoke_all()
        {
           for(auto && fn : _functions)
                fn();
        }
    private:
        std::vector<std::function<void()>> _functions;
};

これで、関数とファンクターを格納するために使用できます。

void myfunction() { std::cout << "myfunction" << std::endl ; }

struct myfunctor
{
       void operator()() { std::cout << "myfunctor" << std::endl ; }
};

A a;
a.add(myfunction);   //add function
a.add(myfunctor());  //add functor!
a.invoke_all();

出力(オンラインデモ):

myfunction
myfunctor

お役に立てば幸いです。

于 2013-02-28T06:00:20.460 に答える
1

関数ポインタは、次のようにするとはるかに読みやすくなりますtypedefs

typedef void (*RequiredFunction)();

addThingy()次に、次のように宣言できます。

    void addThingy(RequiredFunction function);

そしてvectoroffunctionsそのように:

    std::vector<RequiredFunction> vectoroffunctions;

の定義は次のaddThingyとおりです。

void SomeClass::addThingy(RequiredFunction function)
{
    vectoroffunctions.push_back(function);
}

そして、あなたmain()はもっと次のようになります:

int main()
{
    SomeClass sc;
    RequiredFunction pointerfunc = somefunction;
    sc.addThingy(pointerfunc);
    sc.actionWithDiffrentOutcomes();
}

間違いを犯すのは*はるかに少ないです!&

于 2013-02-28T06:05:00.793 に答える