c++ - কেন বঞ্চিত শ্রেণির একটি বর্ধিত ফাংশন বেস বর্গের অন্যান্য ওভারলোড লুকিয়ে রাখে?



polymorphism in biology (3)

আপনার প্রশ্নের শব্দের দ্বারা বিচার করা (আপনি "লুকান" শব্দটি ব্যবহার করেছেন), আপনি ইতিমধ্যে জানেন কি হচ্ছে। ঘটনাটি "নাম গোপন করা" বলা হয়। কিছু কারণে, প্রত্যেকের নাম নাম গোপন হওয়ার সময় সম্পর্কে কোন প্রশ্ন জিজ্ঞেস করে, যে ব্যক্তিরা প্রতিক্রিয়া জানায় যে এটি "নাম গোপন করে" বলে এবং এটি কীভাবে কাজ করে তা ব্যাখ্যা করে (যা সম্ভবত আপনি ইতিমধ্যে জানেন), বা এটি কীভাবে ওভাররাইড করবেন তা ব্যাখ্যা করে (যা আপনি সম্পর্কে জিজ্ঞাসা না), কিন্তু কেউ প্রকৃত "কেন" প্রশ্ন মোকাবেলার যত্ন মনে হয়।

সিদ্ধান্ত, গোপন নামটির পিছনে যুক্তি, অর্থাত এটি আসলে সি ++ এ ডিজাইন করা হয়েছিল কেন, এটি কিছুটা জটিল, অপ্রত্যাশিত এবং সম্ভাব্য বিপজ্জনক আচরণ এড়াতে পারে যা যদি ওভারলোড হওয়া ফাংশনগুলির উত্তরাধিকারসূত্রে সেট করা বর্তমান সেটের সাথে মিশে দেওয়া হয় তবে প্রদত্ত বর্গ overloads। আপনি সম্ভবত জানেন যে সি ++ ওভারলোড রেজোলিউশন প্রার্থীদের সেট থেকে সেরা ফাংশন নির্বাচন করে কাজ করে। এটি পরামিতিগুলির ধরনগুলিতে আর্গুমেন্টগুলির ধরনগুলির সাথে মিলিয়ে সম্পন্ন করা হয়। ম্যাচিং নিয়মগুলি মাঝে মাঝে জটিল হতে পারে এবং প্রায়শই এমন ফলাফলগুলি হতে পারে যা অপ্রয়োজনীয় ব্যবহারকারী দ্বারা অযৌক্তিক বলে মনে করা যেতে পারে। পূর্ববর্তী বিদ্যমানগুলির একটি সেটে নতুন ফাংশন যোগ করার ফলে ওভারলোড রেজোলিউশন ফলাফলগুলির পরিবর্তে পরিবর্তে পরিবর্তিত হতে পারে।

উদাহরণস্বরূপ, আসুন বলি বেস ক্লাস B এর একটি সদস্য ফাংশন foo যা টাইপ void * প্যারামিটার নেয় এবং foo(NULL) এর সমস্ত কলগুলি B::foo(void *) । চলুন বলি যে কোন নাম লুকানো নেই এবং এই B::foo(void *) B থেকে আসা বিভিন্ন শ্রেণীগুলিতে দৃশ্যমান। যাইহোক, আসুন কিছু [পরোক্ষ, দূরবর্তী] উত্তর B ক্লাস B একটি ফাংশন foo(int) সংজ্ঞায়িত করা যাক। এখন, লুকানো নাম ছাড়া D উভয় foo(void *) এবং foo(int) দৃশ্যমান এবং ওভারলোড রেজোলিউশন অংশগ্রহণ করছে। কল কোন ফাংশন foo(NULL) সমাধান করবে, যদি টাইপের কোন বস্তুর মাধ্যমে তৈরি করা হয়? তারা D::foo(int) সমাধান করবে, যেহেতু int কোনও পয়েন্টার টাইপের চেয়ে অবিচ্ছেদ্য শূন্য (অর্থাত NULL ) এর জন্য একটি ভাল মিল। সুতরাং, আধিপত্য জুড়ে foo(NULL) এক ফাংশনে সমাধান করার জন্য কল করে, যখন D (এবং নীচে) তারা হঠাৎ অন্যকে সমাধান করে।

আরেকটি উদাহরণ সি ++ এর ডিজাইন এবং বিবর্তনে দেওয়া হয়েছে, পৃষ্ঠা 77:

class Base {
    int x;
public:
    virtual void copy(Base* p) { x = p-> x; }
};

class Derived{
    int xx;
public:
    virtual void copy(Derived* p) { xx = p->xx; Base::copy(p); }
};

void f(Base a, Derived b)
{
    a.copy(&b); // ok: copy Base part of b
    b.copy(&a); // error: copy(Base*) is hidden by copy(Derived*)
}

এই নিয়ম ছাড়া, বি এর রাষ্ট্র আংশিকভাবে আপডেট করা হবে, slicing নেতৃস্থানীয়।

ভাষা ডিজাইন করা হয় যখন এই আচরণ অযৌক্তিক গণ্য করা হয়েছিল। একটি ভাল পদ্ধতি হিসাবে, এটি "নাম লুকানোর" স্পেসিফিকেশন অনুসরণ করার সিদ্ধান্ত নিয়েছে, যার মানে প্রতিটি শ্রেণীটি ঘোষিত প্রতিটি পদ্ধতির নামের সাথে "পরিচ্ছন্ন শীট" দিয়ে শুরু হয়। এই আচরণটি ওভাররাইড করার জন্য, ব্যবহারকারীর কাছ থেকে একটি স্পষ্ট পদক্ষেপ নেওয়া দরকার: মূলত উত্তরাধিকারী পদ্ধতি (গুলি) (বর্তমানে বর্জন করা) পুনর্বিবেচনা, এখন ঘোষণা-ব্যবহারের একটি সুস্পষ্ট ব্যবহার।

আপনি আপনার মূল পোস্টে সঠিকভাবে পর্যবেক্ষণ করেছেন (আমি "নোট পলিমোফিক" মন্তব্যের কথা উল্লেখ করছি), এই আচরণটি ক্লাসগুলির মধ্যে আইএস-এ সম্পর্কযুক্ত লঙ্ঘন হিসাবে দেখা যেতে পারে। এটি সত্য, কিন্তু আপাতদৃষ্টিতে ফিরে এসে সিদ্ধান্ত নেওয়া হয়েছিল যে শেষ নাম লুকানোর ক্ষেত্রে এটি একটি খারাপ মন্দ হতে পারে।

কোড বিবেচনা করুন:

#include <stdio.h>

class Base {
public: 
    virtual void gogo(int a){
        printf(" Base :: gogo (int) \n");
    };

    virtual void gogo(int* a){
        printf(" Base :: gogo (int*) \n");
    };
};

class Derived : public Base{
public:
    virtual void gogo(int* a){
        printf(" Derived :: gogo (int*) \n");
    };
};

int main(){
    Derived obj;
    obj.gogo(7);
}

এই ত্রুটিটি পেয়েছেন:

>g++ -pedantic -Os test.cpp -o test
test.cpp: In function `int main()':
test.cpp:31: error: no matching function for call to `Derived::gogo(int)'
test.cpp:21: note: candidates are: virtual void Derived::gogo(int*) 
test.cpp:33:2: warning: no newline at end of file
>Exit code: 1

এখানে, ডেরিভেড শ্রেণির ফাংশনটি বেস বর্গের একই নামের (স্বাক্ষর নয়) সমস্ত ফাংশনকে ঘিরে ফেলে। একরকম, সি ++ এই আচরণ ঠিক দেখাচ্ছে না। Polymorphic না।


Answer #1

এই "ডিজাইন দ্বারা" হয়। এই ধরনের পদ্ধতির জন্য সি ++ ওভারলোড রেজোলিউশন নিম্নলিখিত কাজ করে।

  • রেফারেন্সের ধরন থেকে শুরু করে এবং তারপর বেস টাইপ এ গিয়ে প্রথম টাইপটি খুঁজুন যার নাম "gogo"
  • যে ধরনের পদ্ধতিতে "gogo" নামে কেবলমাত্র পদ্ধতিগুলি একটি মিলযুক্ত ওভারলোড খুঁজে পাওয়া যায়

যেহেতু ডেরিভেডটি "gogo" নামক একটি মিলযুক্ত ফাংশন না করে, ওভারলোড রেজোলিউশন ব্যর্থ হয়।


Answer #2

নাম রেজোলিউশন নিয়মগুলি বলে যে নাম সন্ধানটি প্রথম মাপের ক্ষেত্রে বন্ধ হয়ে যায় যা একটি মিলযুক্ত নাম পাওয়া যায়। সেই সময়ে, ওভারলোড রেজোলিউশন নিয়ম উপলব্ধ ফাংশনগুলির সেরা মিল খুঁজে বের করতে kick।

এই ক্ষেত্রে, gogo(int*) ডেরিভেড শ্রেণির স্কোপে পাওয়া যায় (একা), এবং int থেকে int * থেকে কোনও আদর্শ রূপান্তর নেই বলে, সন্ধান ব্যর্থ হয়।

সমাধানটি ডেরিভেড শ্রেণিতে ঘোষিত ঘোষণার মাধ্যমে বেস ঘোষণাগুলি আনতে হয়:

using Base::gogo;

... সকল প্রার্থী খুঁজে পেতে নাম সন্ধানের নিয়মগুলি মঞ্জুর করবে এবং এইভাবে আপনি যতটা প্রত্যাশিত হবেন ততক্ষণ ওভারলোড রেজোলিউশন এগিয়ে যাবে।





override