সদস্য ফাংশন ফাংশন পয়েন্টার


92

আমি ক্লাসের সদস্য হিসাবে একটি ফাংশন পয়েন্টার সেট আপ করতে চাই যা একই ক্লাসের অন্য ফাংশনের পয়েন্টার। যে কারণে আমি এটি করছি তা জটিল।

এই উদাহরণে, আমি আউটপুটটি "1" হতে চাই

class A {
public:
 int f();
 int (*x)();
}

int A::f() {
 return 1;
}


int main() {
 A a;
 a.x = a.f;
 printf("%d\n",a.x())
}

তবে এটি সংকলনে ব্যর্থ। কেন?



@jww এবং এই প্রশ্নে সিরোসন্তিলির জবাব পরীক্ষা করুন, অন্যান্য উত্তরগুলি কম-বেশি বিষয় ছাড়াই। মূলত, just int (C :: * function_pointer_var) (int) = & C :: পদ্ধতি; তারপরে সি সি; এবং (সি। * ফাংশন_পয়েন্টার_ভার) (২)।
jw_

উত্তর:


160

বাক্য গঠনটি ভুল। সদস্য পয়েন্টার একটি সাধারণ পয়েন্টার থেকে আলাদা ধরণের বিভাগ। সদস্য পয়েন্টারটি তার শ্রেণীর একটি সামগ্রীর সাথে একসাথে ব্যবহার করতে হবে:

class A {
public:
 int f();
 int (A::*x)(); // <- declare by saying what class it is a pointer to
};

int A::f() {
 return 1;
}


int main() {
 A a;
 a.x = &A::f; // use the :: syntax
 printf("%d\n",(a.*(a.x))()); // use together with an object of its class
}

a.xফাংশনটি কী ডাকা হবে তা এখনও জানায় না। এটি কেবলমাত্র বলে যে আপনি অবজেক্টে সঞ্চিত পয়েন্টারটি ব্যবহার করতে চান a। অপারেটরের aকাছে বাম অপারেন্ড হিসাবে অন্য সময় প্রস্তুত করা ফাংশনটি কীটিকে .*কল করতে হবে তা কম্পাইলারকে জানিয়ে দেবে।


আমি জানি এটি পুরানো, তবে আমি এর ব্যবহার বুঝতে পারি না (a.*a.x)()hy কেন (a.*x)()কাজ করে না?
গৌরব শেগাল

4
@ গাউ কারণ এক্স সুযোগ নেই
জোহানেস স্কাউব - লিটব

13
প্রতিবার এটি ব্যবহার করার সময় আমাকে এটি দেখতে হবে up বাক্য গঠন বিভ্রান্তিকর, তবে আপনি যদি এটি ভেঙে দেন তবে এটি কোনও অর্থবোধ করে না। a.xক্লাস এ এর ​​সদস্য ফাংশনের পয়েন্টার হ'ল পয়েন্টারটিকে *a.xরেফারেন্স দেয় তাই এখন এটি একটি ফাংশন রেফারেন্স। a.(*a.x)ফাংশনটিকে একটি উদাহরণের সাথে "আবদ্ধ" করে (ঠিক যেমন a.f)। (a.(*a.x))এই জটিল বাক্য (a.(*a.x))()গঠনটি গোষ্ঠীকরণের জন্য প্রয়োজনীয়, এবং আসলে aকোনও যুক্তি ছাড়াই পদ্ধতিটি আহ্বান করে ।
jwm


17

স্ট্রিং কমান্ডে সদস্য ফাংশন কল করুন

#include <iostream>
#include <string>


class A 
{
public: 
    void call();
private:
    void printH();
    void command(std::string a, std::string b, void (A::*func)());
};

void A::printH()
{
    std::cout<< "H\n";
}

void A::call()
{
    command("a","a", &A::printH);
}

void A::command(std::string a, std::string b, void (A::*func)())
{
    if(a == b)
    {
        (this->*func)();
    }
}

int main()
{
    A a;
    a.call();
    return 0;
}

(this->*func)();শ্রেণীর নাম সহ ফাংশন পয়েন্টার ঘোষণা করার উপায় এবং মনোযোগ দিনvoid (A::*func)()


11

আপনাকে কোনও ফাংশনের পয়েন্টার নয়, সদস্য ফাংশনে একটি পয়েন্টার ব্যবহার করতে হবে।

class A { 
    int f() { return 1; }
public:
    int (A::*x)();

    A() : x(&A::f) {}
};

int main() { 
   A a;
   std::cout << (a.*a.x)();
   return 0;
}

3

এটি এই পৃষ্ঠার অন্য কোথাও স্টার্লিং উত্তরের উপর ভিত্তি করে, আমার একটি ব্যবহারের কেস ছিল যা তাদের দ্বারা সম্পূর্ণ সমাধান করা হয়নি; পয়েন্টারগুলির একটি ভেক্টরের জন্য ফাংশনগুলিতে নিম্নলিখিত কাজগুলি করুন:

#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>

class A{
public:
  typedef vector<int> (A::*AFunc)(int I1,int I2);
  vector<AFunc> FuncList;
  inline int Subtract(int I1,int I2){return I1-I2;};
  inline int Add(int I1,int I2){return I1+I2;};
  ...
  void Populate();
  void ExecuteAll();
};

void A::Populate(){
    FuncList.push_back(&A::Subtract);
    FuncList.push_back(&A::Add);
    ...
}

void A::ExecuteAll(){
  int In1=1,In2=2,Out=0;
  for(size_t FuncId=0;FuncId<FuncList.size();FuncId++){
    Out=(this->*FuncList[FuncId])(In1,In2);
    printf("Function %ld output %d\n",FuncId,Out);
  }
}

int main(){
  A Demo;
  Demo.Populate();
  Demo.ExecuteAll();
  return 0;
}

এরকম কিছু কার্যকর যদি আপনি সূচকযুক্ত ফাংশনগুলির সাথে কমান্ড ইন্টারপ্রেটার লিখছেন যা প্যারামিটার সিনট্যাক্স এবং সহায়তা টিপস ইত্যাদির সাথে বিবাহ বন্ধনে আবদ্ধ হওয়া প্রয়োজন সম্ভবত মেনুতেও কার্যকর।


4
সংজ্ঞায়িত হিসাবে, AFunc সদস্য দুটি ফাংশন গ্রহণ করে এবং ints এর একটি ভেক্টর ফিরে ফাংশন একটি পয়েন্টার । তবে সদস্যরা ফিরে আসার ইঙ্গিত করলেন , তাই না? আমি মনে করি typedef int (A::*AFunc)(int I1,int I2);
টাইপিডেফ

3

আপনি দুর্ভাগ্যক্রমে কোনও বিদ্যমান সদস্য ফাংশন পয়েন্টারকে একটি সরল ফাংশন পয়েন্টারে রূপান্তর করতে পারবেন না, আপনি এমন একটি অ্যাডাপ্টার ফাংশন টেম্পলেটটি মোটামুটি সোজা উপায়ে তৈরি করতে পারেন যা কোনও সাধারণ ফাংশনে সংকলন সময়ে পরিচিত সদস্য ফাংশন পয়েন্টারকে আবৃত করে:

template <class Type>
struct member_function;

template <class Type, class Ret, class... Args>
struct member_function<Ret(Type::*)(Args...)>
{
    template <Ret(Type::*Func)(Args...)>
    static Ret adapter(Type &obj, Args&&... args)
    {
        return (obj.*Func)(std::forward<Args>(args)...);
    }
};

template <class Type, class Ret, class... Args>
struct member_function<Ret(Type::*)(Args...) const>
{
    template <Ret(Type::*Func)(Args...) const>
    static Ret adapter(const Type &obj, Args&&... args)
    {
        return (obj.*Func)(std::forward<Args>(args)...);
    }
};

 

int (*func)(A&) = &member_function<decltype(&A::f)>::adapter<&A::f>;

নোট করুন যে সদস্য ফাংশনটি কল করতে, Aঅবশ্যই একটি উদাহরণ সরবরাহ করা উচিত।


আপনি আমাকে অনুপ্রাণিত করেছেন, @ ইলিডান এস 4। আমার উত্তর দেখুন। +1
স্মৃতি

1

@ IllidanS4 এর উত্তরে বিল্ডিং, আমি একটি টেম্পলেট শ্রেণি তৈরি করেছি যা কার্যত কোনও সদস্য ফাংশনটিকে পূর্বনির্ধারিত যুক্তি এবং শ্রেণীর উদাহরণ সহ পরবর্তী কলিংয়ের জন্য রেফারেন্স দিয়ে পাস করার অনুমতি দেয়।



template<class RET, class... RArgs> class Callback_t {
public:
    virtual RET call(RArgs&&... rargs) = 0;
    //virtual RET call() = 0;
};

template<class T, class RET, class... RArgs> class CallbackCalltimeArgs : public Callback_t<RET, RArgs...> {
public:
    T * owner;
    RET(T::*x)(RArgs...);
    RET call(RArgs&&... rargs) {
        return (*owner.*(x))(std::forward<RArgs>(rargs)...);
    };
    CallbackCalltimeArgs(T* t, RET(T::*x)(RArgs...)) : owner(t), x(x) {}
};

template<class T, class RET, class... Args> class CallbackCreattimeArgs : public Callback_t<RET> {
public:
    T* owner;
    RET(T::*x)(Args...);
    RET call() {
        return (*owner.*(x))(std::get<Args&&>(args)...);
    };
    std::tuple<Args&&...> args;
    CallbackCreattimeArgs(T* t, RET(T::*x)(Args...), Args&&... args) : owner(t), x(x),
        args(std::tuple<Args&&...>(std::forward<Args>(args)...)) {}
};

পরীক্ষা / উদাহরণ:

class container {
public:
    static void printFrom(container* c) { c->print(); };
    container(int data) : data(data) {};
    ~container() {};
    void print() { printf("%d\n", data); };
    void printTo(FILE* f) { fprintf(f, "%d\n", data); };
    void printWith(int arg) { printf("%d:%d\n", data, arg); };
private:
    int data;
};

int main() {
    container c1(1), c2(20);
    CallbackCreattimeArgs<container, void> f1(&c1, &container::print);
    Callback_t<void>* fp1 = &f1;
    fp1->call();//1
    CallbackCreattimeArgs<container, void, FILE*> f2(&c2, &container::printTo, stdout);
    Callback_t<void>* fp2 = &f2;
    fp2->call();//20
    CallbackCalltimeArgs<container, void, int> f3(&c2, &container::printWith);
    Callback_t<void, int>* fp3 = &f3;
    fp3->call(15);//20:15
}

স্পষ্টতই, যদি কেবলমাত্র প্রদত্ত যুক্তি এবং মালিক শ্রেণি বৈধ থাকে তবে এটি কাজ করবে। যতদূর পঠনযোগ্যতা ... দয়া করে আমাকে ক্ষমা করুন।

সম্পাদনা: টিপলটিকে সাধারণ স্টোরেজ করে অপ্রয়োজনীয় ম্যালোক সরানো হয়েছে। রেফারেন্সের জন্য উত্তরাধিকারসূত্রে প্রাপ্ত টাইপ। পরিবর্তে কলটাইমে সমস্ত যুক্তি সরবরাহ করার জন্য বিকল্প যুক্ত করা হয়েছে। এখন উভয় থাকার উপর কাজ ....

সম্পাদনা 2: প্রতিশ্রুতি হিসাবে, উভয়। কেবলমাত্র সীমাবদ্ধতা (যা আমি দেখছি) হ'ল কলব্যাক ফাংশনে রানটাইম সরবরাহ করা যুক্তিগুলির আগে পূর্বনির্ধারিত আর্গুমেন্টগুলি অবশ্যই আসতে হবে। জিসিসি সম্মতিতে কিছু সহায়তার জন্য @ শিপস্টারকে ধন্যবাদ। এটি উইন্ডোতে উবুন্টুতে জিসিসি এবং ভিজ্যুয়াল স্টুডিওতে কাজ করে।

#ifdef _WIN32
#define wintypename typename
#else
#define wintypename
#endif

template<class RET, class... RArgs> class Callback_t {
public:
    virtual RET call(RArgs... rargs) = 0;
    virtual ~Callback_t() = default;
};

template<class RET, class... RArgs> class CallbackFactory {
private:
    template<class T, class... CArgs> class Callback : public Callback_t<RET, RArgs...> {
    private:
        T * owner;
        RET(T::*x)(CArgs..., RArgs...);
        std::tuple<CArgs...> cargs;
        RET call(RArgs... rargs) {
            return (*owner.*(x))(std::get<CArgs>(cargs)..., rargs...);
        };
    public:
        Callback(T* t, RET(T::*x)(CArgs..., RArgs...), CArgs... pda);
        ~Callback() {};
    };
public:
    template<class U, class... CArgs> static Callback_t<RET, RArgs...>* make(U* owner, CArgs... cargs, RET(U::*func)(CArgs..., RArgs...));
};
template<class RET2, class... RArgs2> template<class T2, class... CArgs2> CallbackFactory<RET2, RArgs2...>::Callback<T2, CArgs2...>::Callback(T2* t, RET2(T2::*x)(CArgs2..., RArgs2...), CArgs2... pda) : x(x), owner(t), cargs(std::forward<CArgs2>(pda)...) {}
template<class RET, class... RArgs> template<class U, class... CArgs> Callback_t<RET, RArgs...>* CallbackFactory<RET, RArgs...>::make(U* owner, CArgs... cargs, RET(U::*func)(CArgs..., RArgs...)) {
    return new wintypename CallbackFactory<RET, RArgs...>::Callback<U, CArgs...>(owner, func, std::forward<CArgs>(cargs)...);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.