web-dev-qa-db-ja.com

関数定義がメインにあるクラス内の関数ポインターのベクトルからC ++を呼び出す

さて、私のメインでは:

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 ++の本、グーグル、extを読みました。これは正しいように見え、コンパイル、実行されますが、「actionWithDiffrentOutcomes()」を呼び出すと、アクセス違反が発生します。どうすればいいかわかりません。それは正しいようですが、何かが明らかに間違っています。それで、定義が別の中にあるときに、クラス内から関数を呼び出すにはどうすればよいですか?

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

11
Steven Venham

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

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

//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);
}

また、残りのコードには多くの構文エラーがあり、コードのコンパイルを停止する必要があります。

15
Mankarse

問題はここにあります:

vectoroffunctions.Push_back(&function);

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

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

まずこれを変える

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

お役に立てば幸いです。

9
Nawaz

関数ポインタは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();
}
_

間違いを犯す_*_ sと_&_ sがはるかに少ない!

1
Johnsyweb