C ++، التكافؤ بين مؤشر إلى وظائف ومؤشر إلى أعضاء ظائف؟

StackOverflow https://stackoverflow.com/questions/411114

  •  03-07-2019
  •  | 
  •  

سؤال

وأنا معتاد على التفكير في وظائف الأعضاء بأنها مجرد حالة خاصة من الوظائف العادية، حيث لديها وظائف الأعضاء معلمة إضافية في بداية قائمة المعلمات من أجل 'هذا' مؤشر، أي الكائن الذي ومن المفترض الدالة العضو للتحرك. لقد استعملت دفعة :: وظيفة بهذه الطريقة في الماضي أبدا واجهت أي مشاكل:

boost::function f<(void)(MyObject*, int, int)> = &MyObject::method_that_takes_two_ints;

ولكن رأيت هذه الجملة من أجل المؤشرات أعضاء وظيفة:

void (MyObject::*f)( int, int ) = &MyObject::method_that_takes_two_ints;

في بناء الجملة هذا، فإن "هذه" المعلمة غير مرئية. التي حصلت لي أتساءل عما اذا كان تحت غطاء محرك السيارة مؤشر إلى الأعضاء الوظائف هي حقا وحشا مستقل، وأن دفعة ورعاية من التفاصيل بالنسبة لي.

وماذا معيار تملي حول موضع "هذا" المعلمة؟ ربما فقط على مترجم بلدي "هذه حجة إضافية تأتي في المقام الأول، وربما على المجمعين أخرى يمكن أن يكون في نهاية المطاف؟ أنا محظوظ أن طريقتي في التفكير تتفق مع كيف لي المجمعين (GCC4، VS2005) التعامل معها؟ هل مؤشر إلى أعضاء ظائف مجرد حالة خاصة من رمية إلى وظائف مع معلمة إضافية أو يمكن للمترجم تنفيذها بشكل مختلف؟ دائما

هل كانت مفيدة؟

المحلول

والمعيار يقول شيئا عن المكان الذي يجب أن توضع مؤشر this، وفي واقع الأمر هو شائع الى حد كبير لاستخدام اصطلاح استدعاء مختلفة لوظائف الأعضاء. (لذا فإن "هذا" المؤشر ليس مجرد حجة الأولى إضافية، فإنه يتم تخزينها في الواقع في مكان آخر من الأرجنتين الأول عادة ما يكون)

وعلى وجه الخصوص، يستخدم MSVC من thiscall استدعاء اصطلاح لوظائف الأعضاء، وstdcall في مكان آخر. http://www.hackcraft.net/cpp/MSCallingConventions/#thiscall يصف الخلافات بينهما، ولكن لاحظ أن thiscall مخازن مؤشر this في السجل ECX، في حين مخازن stdcall <م> جميع المعلمات على المكدس.

وأنت بالتأكيد أفضل حالا التعامل معها بوصفها أنواع متميزة تماما. مؤشر إلى دالة عضو هو <م> لا مجرد مؤشر دالة مع معلمة إضافية.

نصائح أخرى

لا تخزين مؤشر this على طول مؤشر إلى عضو (مؤشرات دالة عضو هي حالة خاصة من هذا). إذا كنت تفعل ذلك تماما

void (MyObject::*f)( int, int ) = &MyObject::method_that_takes_two_ints;

وماذا بعد ذلك يتم تخزينها هو مجرد معلومات التي ينبغي أن تسمى ظيفة عضو في أوبجكت التي لديك في وقت لاحق لتقديم. إذا كنت تريد أن نسميها، لديك لتمرير كائن جنبا إلى جنب، حيث المترجم سوف تحصل على مؤشر this من.

MyObject o; (o.*f)(1, 2);

ومؤشر دالة عضو هو مجرد مؤشر العضو الذي نوع (وهذا ما أشار إلى) هو نوع وظيفة. يقول المعيار أن المؤشرات الدالة العضو لا تملك الخاصة "نوع الدالة العضو" بأنهم تشير إلى والتي من شأنها أن تشمل بطريقة ما نوع هذا المؤشر.

int main() {
    typedef void fun() const;
    fun MyObject::*mem_function_ptr = 
        &MyObject::const_method_that_takes_two_ints;
}

وfun في هذا الرمز هو نوع وظيفة. النوع الذي وظيفة "طبيعية" لديها. وظيفة مؤشر ل، في مقابل الأعضاء الوظائف المؤشر، هو مجرد مؤشر دالة وجود هذا النوع:

void foo() { cout << "hello"; }
int main() {
    typedef void fun();
    fun * f = &foo;
}

وعلى الرغم عضوا وظيفة مؤشر إلى ديه مستوى إضافي الأعضاء المؤشر على أعلى من هذا النوع وظيفة.

وشيء مؤشر this ومدى ارتباطه الكائن الذي يشير إلى (وليس تقني، فقط الاشياء النظري):

وكل دالة عضو له معلمة خفية تسمى implicit object parameter التي لديها اكتب MyObject& أو MyObject const& اعتمادا على ما إذا كان لديك CONST أو دالة عضو nonconst. الكائن الذي استدعاء ظيفة عضو في، o، هو implied object argument، التي يتم تمريرها إلى المعلمة. في نظرية المعيار الذي تشكل القواعد التي تصف كيف تسمى وظائف الأعضاء، والمعلمة الكائن الضمنية هي أول معلمة المخفية. هذا المفاهيمي، وهذا لا يعني انها قضية حقيقية في التنفيذ. ثم لا بد من حجة الكائن ضمنية إلى أن المعلمة الكائن ضمنية، ربما تسبب تحويلات ضمنية (حتى في حالة استدعاء دالة عضو CONST على كائن غير CONST، تحويل التأهيل يحول من MyObject إلى MyObject const&، وهذا ما يجعل وظائف غير CONST خيارا أفضل من وظائف CONST للدعوة، لكائن غير CONST). على سبيل المثال، يمكن للمرء أن يقول في هذا الرمز:

struct A {
    operator int() const { return 0; }
};

int main() { 
    A a;
    int i = a; // implicit conversion using the conversion function
}

وهذا لا بد من ضمني a حجة كائن من نوع A إلى المعلمة الكائن ضمنية من نوع A const&، الذي ثم يتم التوجه إليه من قبل مؤشر this وجود نوع A const* هنا الكائن. من المهم أن نلاحظ أن المعلمة الكائن ضمنية ليست سوى بناء نظري، لإضفاء الطابع الرسمي على الطريقة التي يتم بها قواعد لاستدعاء دالة عضو حتى (والصانعين لا تشمل منهم)، في حين أن هذا المؤشر هو موجود في الواقع. this هو مؤشر، لأنه عندما قدم this، C ++ لم يكن لديك ما يشير حتى الان.

وآمل أن تساعدك على فهم هذه المسألة.

ومقال ممتازة على مؤشرات دالة عضو هو المؤشرات الدالة الأعضاء وأسرع وقت ممكن C ++ المندوبين . توضح هذه المقالة مؤشرات دالة عضو من الحالات البسيطة على طول الطريق من خلال المؤشرات الدالة العضو الظاهري مع وراثة متعددة. على سبيل المكافأة، فإنه يوفر تنفيذ الوفود التي يمكن أن تكون مفيدة حقا.

نعم، مؤشرات إلى وظائف ومؤشرات إلى أعضاء وحوش مختلفة تماما. تحتاج إلى إعطاء مثيل كائن إلى أن محتويات المؤشر باستخدام ->* أو .* مشغلي مؤشرات للأعضاء. ليس هناك المعلمة this تستخدم عند اتخاذ رمية لأعضاء ليتم تحديد this عند استخدام مؤشر إلى عضو (الكائن على يسار ->* أو .*).

لاحظ هناك على الأرجح أقل من الفرق بين وظيفة مؤشر إلى الأعضاء ومتغير مؤشر إلى عضو من هناك بين وظيفة مؤشر إلى الأعضاء ومؤشر دالة منتظم.

وعادة وظائف الأعضاء والوظائف العادية يمكن أن يكون اصطلاحات الاستدعاء مختلفة تماما بحيث لا يمكن أن يلقي بينهما.

لاحظ أن حجم مؤشر إلى عضو وظيفة قد تكون مختلفة باستخدام المجمعين مختلفة.

وشيء آخر أن نلاحظ، كما هو مكتوب في القديمة الجديدة الشيء بلوق :

<اقتباس فقرة>   

ووحجم   رمية لأعضاء وظيفة يمكن أن تغير   اعتمادا على الطبقة.

وهم بالتأكيد أنواع متميزة وأي افتراضات جعل لكم سوف تكون منصة / مترجم معين.

هذه الصفحة لديه المزيد من المعلومات حول تنفيذ النقاط الدالة العضو من أردت أن تعرف، بما في ذلك تفاصيل التنفيذ للعديد من المجمعين الشعبية.

للرد على جميع الأسئلة: نعم، انهم مؤشرات خاصة، مختلفة من المؤشرات العادية. نعم، وتعزيز وظيفة :: تعترف لهم.

وهذا المعيار لا يقول شيئا عن التفاصيل الداخلية للمداخن المكالمة. في الواقع، قد تستخدم العديد من المجمعين rergisters صحيح، سجلات نقطة عائمة، و / أو كومة اعتمادا على قائمة الوسائط الفعلية. A 'هذا' مؤشر هو مجرد حالة واحدة أكثر خاصة.

ودفعة :: وظيفة يحل هذه باستخدام مسارين كود داخليا. يمكنك ان ترى هذا عن طريق فحص مكدس الاستدعاءات للحالتين. إذا كان لديك دفعة :: وظيفة بتخزين مؤشر إلى وظيفة الأعضاء، فإن المشغل () تقسيم قائمة وسيطة. يستخدم الوسيطة الأولى كما الكائن الذي يسمى الدالة العضو مع الحجج المتبقية.

لتكملة الجواب الجميع، ويعمل عن طريق Boost.Function متخصصة عامل التعيين على مؤشرات دالة عضو، للسماح له للكشف عند مرت واحد. عند استدعاء هذه الوظيفة، فإنه سيتم إعادة تفسير داخليا إلى الأسلوب المناسب لاستدعاء مؤشر دالة عضو ((obj->*fun)(args)).

وأعتقد أنك قد تجد هذا الرابط جدا للاهتمام:

http://www.parashift.com/c++ -faq لايت / مؤشرات إلى members.html

وانها صفا جيدا للغاية من كل شيء كنت تريد أن تعرف عن مؤشر إلى الأعضاء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top