অপারেটর ওভারলোডিংয়ের জন্য মৌলিক নিয়ম এবং আইডিয়ামগুলি কী কী?


2140

দ্রষ্টব্য: উত্তরগুলি একটি নির্দিষ্ট ক্রমে দেওয়া হয়েছিল , তবে যেহেতু অনেক ব্যবহারকারী ভোট দেওয়ার সাথে সাথে উত্তরগুলি সাজান, তার চেয়ে যে সময় দেওয়া হয়েছিল তার চেয়ে বেশি, তাই উত্তরের ক্রম অনুসারে উত্তরগুলির একটি সূচক এখানে দেওয়া হয়েছে :

(দ্রষ্টব্য: এই একটি এন্ট্রি হতে বোঝানো হয় স্ট্যাক ওভারফ্লো সি ++ প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী । আপনি তারপর, এই ফর্মে একটি প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী প্রদান ধারণা সমালোচনা করতে চান, মেটা যে শুরু এই সব পোস্টিং । যে কাজ করতে জায়গা হবে উত্তর সেই প্রশ্নটি সি ++ চ্যাটরুমে পর্যবেক্ষণ করা হয় , যেখানে এফএকিউ ধারণাটি প্রথম স্থানে শুরু হয়েছিল, সুতরাং আপনার উত্তরটি যারা ধারণাটি নিয়ে এসেছিল তারা খুব সম্ভবত পঠন করতে পারে।)


63
যদি আমরা সি ++ - এফএকিউ ট্যাগ দিয়ে চালিয়ে যাচ্ছি তবে এন্ট্রিগুলি ফর্ম্যাট করা উচিত।
জন ডিবলিং

অপারেটর ওভারলোডিং সম্পর্কে জার্মান সি ++ সম্প্রদায়ের জন্য আমি একটি সংক্ষিপ্ত সিরিজের নিবন্ধ লিখেছি: পর্ব 1: সি ++ এ অপারেটর ওভারলোডিং সমস্ত শব্দগুলির অপারেটরগুলির জন্য শব্দার্থবিজ্ঞান, সাধারণ ব্যবহার এবং বিশেষত্বগুলি কভার করে। এখানে আপনার উত্তরগুলির সাথে কিছু ওভারল্যাপিংস রয়েছে তবুও কিছু অতিরিক্ত তথ্য রয়েছে। 2 এবং 3 এর অংশগুলি বুস্ট.অ্যাপ্রেটারগুলি ব্যবহারের জন্য একটি টিউটোরিয়াল তৈরি করে। আপনি কি তাদের পছন্দ করতে এবং উত্তর হিসাবে সেগুলি যুক্ত করতে চান?
আরনে মের্টজ

ওহ, এবং একটি ইংরেজি
অনুবাদও

উত্তর:


1042

সাধারণ লোকেদের ওভারলোড করার জন্য

ওভারলোডিং অপারেটরগুলির বেশিরভাগ কাজ হ'ল বয়লার-প্লেট কোড। এটি আশ্চর্যের কিছু নয় যেহেতু অপারেটরগুলি নিছক সিনট্যাকটিক চিনি, তাই তাদের আসল কাজটি সরল ফাংশন দ্বারা (এবং প্রায়শই ফরোয়ার্ড করা হয়) করা যেতে পারে। তবে এটি গুরুত্বপূর্ণ যে আপনি এই বয়লার-প্লেট কোডটি সঠিকভাবে পান। আপনি যদি ব্যর্থ হন তবে হয় আপনার অপারেটরের কোডটি সংকলন করবে না বা আপনার ব্যবহারকারীর কোড সংকলন করবে না বা আপনার ব্যবহারকারীর কোডটি আশ্চর্যরকম আচরণ করবে।

নিয়োগ অপারেটর

অ্যাসাইনমেন্ট সম্পর্কে অনেক কিছু বলা দরকার। যাইহোক, এর বেশিরভাগই ইতিমধ্যে GMan এর বিখ্যাত কপি-অ্যান্ড-অদলবদ FAQ এ বলা হয়েছে , সুতরাং আমি এখানে বেশিরভাগটি এড়িয়ে যাব, কেবলমাত্র রেফারেন্সের জন্য নিখুঁত অ্যাসাইনমেন্ট অপারেটরকে তালিকাভুক্ত করব:

X& X::operator=(X rhs)
{
  swap(rhs);
  return *this;
}

বিটশিফ্ট অপারেটর (I / O স্ট্রিমের জন্য ব্যবহৃত)

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

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

std::ostream& operator<<(std::ostream& os, const T& obj)
{
  // write obj to stream

  return os;
}

std::istream& operator>>(std::istream& is, T& obj)
{
  // read obj from stream

  if( /* no valid object of T found in stream */ )
    is.setstate(std::ios::failbit);

  return is;
}

বাস্তবায়ন করার সময় operator>>, ম্যানুয়ালি স্ট্রিমের স্থিতি সেট করা কেবল তখনই প্রয়োজনীয় যখন পড়া নিজেই সফল হয়েছিল, তবে ফলাফলটি কী প্রত্যাশা করা হবে তা নয়।

ফাংশন কল অপারেটর

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

এখানে সিনট্যাক্সের একটি উদাহরণ রয়েছে:

class foo {
public:
    // Overloaded call operator
    int operator()(const std::string& y) {
        // ...
    }
};

ব্যবহার:

foo f;
int a = f("hello");

পুরো সি ++ স্ট্যান্ডার্ড লাইব্রেরি জুড়ে, ফাংশন অবজেক্টগুলি সর্বদা অনুলিপি করা হয়। আপনার নিজের ফাংশন অবজেক্টগুলি অনুলিপি করার জন্য সস্তা হওয়া উচিত। যদি কোনও ফাংশন অবজেক্টকে একেবারে অনুলিপিযুক্ত ডেটা ব্যবহারের প্রয়োজন হয় তবে সেই ডেটা অন্য কোথাও সঞ্চয় করা এবং ফাংশন অবজেক্টটি এতে উল্লেখ করা ভাল।

তুলনা অপারেটর

বাইনারি ইনফিক্স তুলনা অপারেটরগুলি, থাম্বের নিয়ম অনুসারে, সদস্যবিহীন ফাংশন 1 হিসাবে প্রয়োগ করা উচিত । অ্যানারি উপসর্গের অবহেলা !(একই নিয়ম অনুসারে) সদস্য ফাংশন হিসাবে প্রয়োগ করা উচিত। (তবে এটি ওভারলোড করা সাধারণত ভাল ধারণা নয়))

স্ট্যান্ডার্ড লাইব্রেরির অ্যালগোরিদম (যেমন std::sort()) এবং প্রকারগুলি (যেমন std::map) সবসময় কেবল operator<উপস্থিত থাকার প্রত্যাশা করবে expect তবে, আপনার ধরণের ব্যবহারকারীরা অন্যান্য অপারেটরদের উপস্থিত থাকারও প্রত্যাশা করবেন , সুতরাং আপনি যদি সংজ্ঞায়িত করেন তবে operator<অপারেটর ওভারলোডিংয়ের তৃতীয় মৌলিক নিয়মটি অনুসরণ করা এবং অন্যান্য সমস্ত বুলিয়ান তুলনা অপারেটরগুলি সংজ্ঞায়িত করতে ভুলবেন না। এগুলি বাস্তবায়নের প্রচলিত উপায় হ'ল:

inline bool operator==(const X& lhs, const X& rhs){ /* do actual comparison */ }
inline bool operator!=(const X& lhs, const X& rhs){return !operator==(lhs,rhs);}
inline bool operator< (const X& lhs, const X& rhs){ /* do actual comparison */ }
inline bool operator> (const X& lhs, const X& rhs){return  operator< (rhs,lhs);}
inline bool operator<=(const X& lhs, const X& rhs){return !operator> (lhs,rhs);}
inline bool operator>=(const X& lhs, const X& rhs){return !operator< (lhs,rhs);}

এখানে লক্ষণীয় গুরুত্বপূর্ণ বিষয় হ'ল এই অপারেটরগুলির মধ্যে মাত্র দুটি প্রকৃতপক্ষে কিছু করে, অন্যরা তাদের যুক্তিগুলি প্রকৃত কাজটি করার জন্য এই দুজনের কোনওটির কাছেই প্রেরণ করছে।

অবশিষ্ট বাইনারি বুলিয়ান অপারেটরগুলি ( ||, &&) ওভারলোড করার বাক্য গঠন তুলনা অপারেটরগুলির বিধি অনুসরণ করে। তবে, আপনি এই 2 এর জন্য যুক্তিসঙ্গত ব্যবহারের কেসটি খুঁজে পাবেন এমনটি খুব কমই ।

1 থাম্বের সমস্ত নিয়মের মতো, কখনও কখনও এটিও ভাঙার কারণ থাকতে পারে। যদি তা হয় তবে ভুলে যাবেন না যে বাইনারি তুলনা অপারেটরগুলির বাম-হাতের ক্রিয়াকলাপ, যা সদস্য ফাংশনগুলির জন্য হবে তাও হওয়া *thisদরকার const। সুতরাং কোনও সদস্য কার্য হিসাবে প্রয়োগ করা তুলনা অপারেটরের এই স্বাক্ষর থাকতে হবে:

bool operator<(const X& rhs) const { /* do actual comparison with *this */ }

( constশেষে নোট করুন ।)

2 এটি লক্ষ করা উচিত যে শর্টকাট শব্দার্থবিজ্ঞানের অন্তর্নির্মিত সংস্করণ ||এবং &&ব্যবহার। ব্যবহারকারী সংজ্ঞায়িত ব্যক্তিদের (কারণ তারা পদ্ধতি কলগুলির জন্য সিনট্যাকটিক চিনি) শর্টকাট শব্দার্থবিজ্ঞান ব্যবহার করে না। ব্যবহারকারীরা অপারেটরদের শর্টকাট শব্দার্থবিজ্ঞানের প্রত্যাশা করবেন, এবং তাদের কোড এটির উপর নির্ভর করতে পারে, সুতরাং এগুলি সংজ্ঞায়িত করার জন্য এটি অত্যন্ত পরামর্শ দেওয়া হয় না।

পাটিগণিত অপারেটর

অ্যানারি গণিত অপারেটর

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

class X {
  X& operator++()
  {
    // do actual increment
    return *this;
  }
  X operator++(int)
  {
    X tmp(*this);
    operator++();
    return tmp;
  }
};

নোট করুন যে পোস্টফিক্স রূপটি উপসর্গের ক্ষেত্রে প্রয়োগ করা হয়েছে। এছাড়াও নোট করুন যে পোস্টফিক্স একটি অতিরিক্ত অনুলিপি করে। 2

ওভারলোডিং অ্যানারি মাইনাস এবং প্লাস খুব সাধারণ নয় এবং সম্ভবত সেরা এড়ানো হবে। যদি প্রয়োজন হয় তবে তাদের সম্ভবত সদস্য ফাংশন হিসাবে ওভারলোড করা উচিত।

2 এছাড়াও নোট করুন যে পোস্টফিক্স বৈকল্পিক আরও বেশি কাজ করে এবং তাই উপসর্গের বৈকল্পিকের চেয়ে কম দক্ষ। পোস্টফিক্স ইনক্রিমেন্টের চেয়ে সাধারণত প্রিফিক্স ইনক্রিমেন্ট পছন্দ করা এটি একটি ভাল কারণ। সংকলকরা সাধারণত অন্তর্নির্মিত প্রকারের জন্য পোস্টফিক্স ইনক্রিমেন্টের অতিরিক্ত কাজটি অপ্টিমাইজ করতে পারে তবে তারা ব্যবহারকারী-সংজ্ঞায়িত প্রকারের জন্য একই কাজ করতে সক্ষম না হতে পারে (যা নিরীহভাবে তালিকার পুনরুক্তিকারীর মতো দেখার মতো কিছু হতে পারে)। একবার আপনি অভ্যস্ত i++হয়ে যাওয়ার পরে কোনও বিল্ট-ইন টাইপ না হওয়ার ++iপরিবর্তে এটি মনে রাখা খুব শক্ত হয়ে যায় i(কোনও টাইপ পরিবর্তন করার সময় আপনার কোডটি পরিবর্তন করতে হবে), তাই সর্বদা অভ্যাস করা ভাল always প্রিফিক্স ইনক্রিমেন্ট ব্যবহার করা, যদি না পোস্টফিক্সের স্পষ্টভাবে প্রয়োজন হয়।

বাইনারি গাণিতিক অপারেটর

বাইনারি গাণিতিক অপারেটরদের জন্য ভুলবেন না তৃতীয় মৌলিক নিয়ম অপারেটর ওভারলোডিং মান্য করা: আপনি প্রদান তাহলে +, এছাড়াও প্রদান +=, যদি আপনি প্রদান -, না ফেরত না -=, ইত্যাদি অ্যান্ড্রু Koenig প্রথম পালন করা যে যৌগ নিয়োগ হয়েছে বলা হয় অপারেটরগুলি তাদের অ-যৌগিক অংশগুলির জন্য বেস হিসাবে ব্যবহার করা যেতে পারে। অর্থাৎ অপারেটর হয় +পরিপ্রেক্ষিতে বাস্তবায়িত হয় +=, -পদ বাস্তবায়িত হয় -=ইত্যাদি

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

class X {
  X& operator+=(const X& rhs)
  {
    // actual addition of rhs to *this
    return *this;
  }
};
inline X operator+(X lhs, const X& rhs)
{
  lhs += rhs;
  return lhs;
}

operator+=রেফারেন্স অনুযায়ী operator+তার ফলাফল প্রদান করে, তার ফলাফলের একটি অনুলিপি প্রদান করে। অবশ্যই, কোনও রেফারেন্স ফিরিয়ে দেওয়া সাধারণত অনুলিপি ফেরত দেওয়ার চেয়ে বেশি দক্ষ, তবে এর ক্ষেত্রে operator+অনুলিপি করার কোনও উপায় নেই। আপনি যখন লিখবেন a + b, আপনি ফলাফলটি একটি নতুন মান হিসাবে প্রত্যাশা করবেন, যার কারণে operator+একটি নতুন মান ফিরে আসতে হবে। এছাড়াও নোট করুন যে কনস্ট্রিপ রেফারেন্সের পরিবর্তে অনুলিপি দ্বারাoperator+ বাম অপারেণ্ডটি নিয়েছে । এর কারণ অনুলিপি অনুসারে তার যুক্তি নেওয়ার কারণ হিসাবে একই ।operator=

বিট ম্যানিপুলেশন অপারেটরগুলি ~ & | ^ << >>গণিত অপারেটরগুলির মতো একইভাবে প্রয়োগ করা উচিত। তবে, (ওভারলোডিং <<এবং >>আউটপুট এবং ইনপুট ব্যতীত) এগুলি অতিরিক্ত লোড করার জন্য যুক্তিসঙ্গত ব্যবহারের খুব কম কেস রয়েছে।

আবার এ থেকে যে পাঠ গ্রহণ করা হবে তা a += bহ'ল, সাধারণভাবে তার চেয়েও বেশি দক্ষ a + bএবং যদি সম্ভব হয় তবে তাকে অগ্রাধিকার দেওয়া উচিত।

অ্যারে সাবস্ক্রিপশন

অ্যারে সাবস্ক্রিপ্ট অপারেটর একটি বাইনারি অপারেটর যা অবশ্যই শ্রেণীর সদস্য হিসাবে প্রয়োগ করা উচিত। এটি ধারক-জাতীয় ধরণের জন্য ব্যবহৃত হয় যা কোনও কী দ্বারা তাদের ডেটা উপাদানগুলিতে অ্যাক্সেসের অনুমতি দেয়। এগুলি সরবরাহের আধ্যাত্মিক রূপটি হ'ল:

class X {
        value_type& operator[](index_type idx);
  const value_type& operator[](index_type idx) const;
  // ...
};

আপনি না চাইলে আপনার শ্রেণীর ব্যবহারকারীরা ফিরে আসা ডেটা উপাদানগুলি পরিবর্তন করতে সক্ষম হবেন না operator[](যদি আপনি নন-কনস্ট্যান্ট বৈকল্পিক বাদ দিতে পারেন), আপনার সর্বদা অপারেটরের উভয় রূপই সরবরাহ করা উচিত।

যদি মান_প্রকারটি একটি অন্তর্নির্মিত প্রকারের জন্য উল্লেখ করা হয়, তবে অপারেটরের কনস্টেন্ট রূপটি কনস্ট কনফারেন্সের পরিবর্তে একটি অনুলিপি আরও ভালভাবে ফিরিয়ে আনতে হবে:

class X {
  value_type& operator[](index_type idx);
  value_type  operator[](index_type idx) const;
  // ...
};

পয়েন্টার-জাতীয় টাইপের জন্য অপারেটর

আপনার নিজের পুনরাবৃত্তকারী বা স্মার্ট পয়েন্টারগুলি সংজ্ঞায়িত করার জন্য আপনাকে ইউনারি প্রিফিক্স ডেরিফারেন্স অপারেটর *এবং বাইনারি ইনফিক্স পয়েন্টার সদস্য অ্যাক্সেস অপারেটরটি ওভারলোড করতে হবে ->:

class my_ptr {
        value_type& operator*();
  const value_type& operator*() const;
        value_type* operator->();
  const value_type* operator->() const;
};

নোট করুন যে এগুলিও প্রায় সর্বদা একটি কনস্ট এবং একটি অবিচ্ছিন্ন সংস্করণ উভয়েরই প্রয়োজন। জন্য ->অপারেটর, যদি value_typeহয় class(অথবা structঅথবা unionআরেকটি) টাইপ operator->()যাও recursively বলা হয়, একটি পর্যন্ত operator->()আয় অ বর্গ ধরনের মান।

অবিচ্ছিন্ন ঠিকানা-অপারেটরটি কখনই ওভারলোড করা উচিত নয়।

জন্য operator->*()দেখতে এই প্রশ্নের । এটি খুব কমই ব্যবহৃত হয় এবং এর ফলে খুব কমই কখনও কখনও বোঝা যায়। আসলে, এমনকি পুনরাবৃত্তিকারীরা এটি ওভারলোড করে না।


রূপান্তর অপারেটরগুলিতে চালিয়ে যান


89
operator->()আসলে চরম অদ্ভুত। এটি কোনও ফেরত দেওয়ার প্রয়োজন হয় না value_type*- বাস্তবে, এটি অন্য শ্রেণির ধরণটি ফিরিয়ে দিতে পারে, তবে শর্ত থাকে যে শ্রেণীর ধরণের একটি রয়েছেoperator->() , যা পরবর্তী সময়ে বলা হবে। এর পুনরাবৃত্ত কলিংটি operator->()কোনও value_type*রিটার্ন টাইপ না হওয়া পর্যন্ত এগিয়ে যায়। ম্যাডনেস! :)
j_random_hacker

2
এটি কার্যকারিতা সম্পর্কে ঠিক নয়। এটি একটি (খুব) কয়েকটি ক্ষেত্রে আমরা প্রথাগত-প্রতিচ্ছবিযুক্ত পদ্ধতিতে এটি করতে পারি না: যখন ফলাফলটি গণনা করার সময় উভয় অপারেটরের সংজ্ঞাটি অপরিবর্তিত থাকে। এবং যেমনটি আমি বলেছি, এখানে দুটি ধ্রুপদী উদাহরণ রয়েছে: ম্যাট্রিক্স গুণক এবং বহুবচনগুলির গুণক। আমরা *শর্তে সংজ্ঞায়িত করতে পারলাম *=তবে এটি বিশ্রী হবে কারণ প্রথম ক্রিয়াকলাপের মধ্যে *=একটি নতুন অভিব্যক্তি তৈরির ফলাফল তৈরি করবে। তারপরে, আইজক লুপের পরে, আমরা এই অস্থায়ী বস্তুটির সাথে অদলবদল করব *this। অর্থাত। 1 কপি, 2. অপারেটর *, 3.সপপ্প
লুস হার্মিট

6
আমি const / আপনার পয়েন্টার মত অপারেটর, যেমন `const VALUE_TYPE & অপারেটর * () const অ-const সংস্করণের সাথে অসম্মতি '- এই হচ্ছে মত হবে T* constএকটি ফিরতি const T&dereferencing, যে ক্ষেত্রে নয় উপর। বা অন্য কথায়: একটি কনস্ট পয়েন্টার কোনও কনস্ট পয়েন্টিকে বোঝায় না। আসলে, এটি নকল করা তুচ্ছ নয় T const *- const_iteratorএটি স্ট্যান্ডার্ড লাইব্রেরিতে পুরো স্টাফের কারণ । উপসংহার: স্বাক্ষরটি হওয়া উচিতreference_type operator*() const; pointer_type operator->() const
অ্যার্ন মের্টজ

6
একটি মন্তব্য: বাইনারি গাণিতিক অপারেটরগুলির প্রস্তাবিত প্রয়োগগুলি তেমন দক্ষ নয়। সে বুস্ট অপারেটরদের শিরোনামগুলির সিমিটারি নোট: boost.org/doc/libs/1_54_0/libs/utility/operators.htm# সিমিমেট্রি আপনি যদি প্রথম প্যারামিটারের স্থানীয় কপি ব্যবহার করেন তবে + = করুন, এবং ফিরে আসুন তবে আরও একটি অনুলিপি এড়ানো যাবে স্থানীয় কপি। এটি এনআরভিও অপ্টিমাইজেশন সক্ষম করে।
মনু 343726

3
আমি যেমন আড্ডায় উল্লেখ করেছি, L <= Rতার !(R < L)পরিবর্তেও প্রকাশ করা যেতে পারে !(L > R)। হার্ড-টু-অপ্টিমাইজ করা এক্সপ্রেশনগুলিতে ইনলাইনের একটি অতিরিক্ত স্তর বাঁচাতে পারে (এবং এটি বুস্ট.অ্যাপারেটররা কীভাবে এটি প্রয়োগ করে)।
TemplateRex

494

সি ++ এ অপারেটর ওভারলোডিংয়ের তিনটি বেসিক বিধি

এটি যখন সি ++ এ অপারেটরের ওভারলোডিংয়ের কথা আসে, তখন আপনাকে তিনটি মূল নিয়ম অনুসরণ করা উচিত । যেমন সমস্ত নিয়ম হিসাবে, সত্যিই ব্যতিক্রম আছে। কখনও কখনও লোকেরা তাদের কাছ থেকে বিচ্যুত হয় এবং ফলাফলটি খারাপ কোড ছিল না, তবে এই জাতীয় ইতিবাচক বিচ্যুতিগুলি খুব কম এবং এর মধ্যে রয়েছে। খুব কমপক্ষে, 100 টির মধ্যে 99 টি বিচ্যুতিটি আমি দেখেছি তা ন্যায়বিচারহীন ছিল। তবে এটি 1000 এর মধ্যে 999 হতে পারে So সুতরাং নীচের নিয়মগুলিতে আপনি আরও বেশি আঁকেন d

  1. যখনই কোনও অপারেটরের অর্থ স্পষ্টত পরিষ্কার এবং বিতর্কিত না হয়, তখন এটি ওভারলোড করা উচিত নয়। পরিবর্তে, একটি সুনির্বাচিত নাম সহ একটি ফাংশন সরবরাহ করুন।
    মূলত, ওভারলোডিং অপারেটরগুলির প্রথম এবং সর্বাগ্রে নিয়মটি এর খুব হৃদয়ে বলে: এটি করবেন না । এটি অদ্ভুত বলে মনে হতে পারে, কারণ অপারেটর ওভারলোডিং সম্পর্কে অনেক কিছু জানা যায় এবং তাই অনেকগুলি নিবন্ধ, বইয়ের অধ্যায় এবং অন্যান্য পাঠ্যগুলি এই সমস্ত বিষয় নিয়ে কাজ করে। তবে এই আপাতদৃষ্টিতে সুস্পষ্ট প্রমাণ থাকা সত্ত্বেও কেবলমাত্র আশ্চর্যরকম কিছু ঘটনা রয়েছে যেখানে অপারেটর ওভারলোডিং উপযুক্ত appropriate। কারণটি হ'ল অ্যাপ্লিকেশন ডোমেনে অপারেটরের ব্যবহার সুপরিচিত এবং বিতর্কিত না হলে অপারেটরের প্রয়োগের পেছনের শব্দার্থবিজ্ঞানগুলি বোঝা শক্ত। জনপ্রিয় বিশ্বাসের বিপরীতে, এটি খুব কমই ঘটেনি।

  2. সর্বদা অপারেটরের সুপরিচিত শব্দার্থককে আটকে দিন।
    সি ++ ওভারলোডেড অপারেটরগুলির শব্দার্থবিজ্ঞানের কোনও সীমাবদ্ধতা পোষণ করে না। আপনার সংকলকটি আনন্দের সাথে কোডটি গ্রহণ করবে যা বাইনারি+অপারেটরটিকে তার ডান অপরেন্ড থেকে বিয়োগকরতে প্রয়োগ করে। তবে, এই জাতীয় অপারেটরের ব্যবহারকারীরা কখনইa + bভাবটিaথেকেবিয়োগ করতেসন্দেহ করবেন নাb। অবশ্যই, এটি অনুমান করে যে অ্যাপ্লিকেশন ডোমেনে অপারেটরের শব্দার্থবিবাদ বিতর্কিত।

  3. সর্বদা সম্পর্কিত ক্রিয়াকলাপের সেট সরবরাহ করুন।
    অপারেটরগুলি একে অপরের সাথে এবং অন্যান্য অপারেশনের সাথে সম্পর্কিত । যদি আপনার ধরণটি সমর্থন করে তবেa + bব্যবহারকারীরাও কল করতে পারবেন বলে আশা করবেa += b। যদি এটি উপসর্গ বর্ধনকে সমর্থন করে তবে++aতারাa++কাজকরারওআশা করবে। যদি তারা যাচাই করতে পারে তবে তারাa < bঅবশ্যই প্রত্যাশা করবে যে এটি চেক করতে সক্ষম হবে কিনাa > b। যদি তারা আপনার প্রকারের অনুলিপি তৈরি করতে পারে তবে তারা কাজটিও কাজ করার আশা করে।


সদস্য এবং অ-সদস্যের মধ্যে সিদ্ধান্ত অবিরত করুন ।


16
এর মধ্যে কেবলমাত্র আমি সচেতন যা এইগুলির যে কোনও একটি লঙ্ঘন করে তা হ'ল boost::spiritলোল।
বিলি ওনিল

66
@ বিলি: কারও মতে +স্ট্রিং কনটেনটেশনের জন্য অপব্যবহার করা লঙ্ঘন, তবে এটি এখন সুপ্রতিষ্ঠিত প্রক্সি হয়ে উঠেছে, যাতে এটি প্রাকৃতিক বলে মনে হয়। যদিও আমি 90-এর দশকে একটি হোম-ব্রিউ স্ট্রিং ক্লাসের কথা মনে করি যা &এই উদ্দেশ্যে বাইনারি ব্যবহার করে (প্রতিষ্ঠিত প্রক্সিগুলির জন্য বেসিককে উল্লেখ করে)। তবে, হ্যাঁ, এটিকে মূল স্ট্যান্ডের মধ্যে রেখে পাথরে সেট করুন। একই অপব্যবহারের জন্য <<এবং >>আইও, বিটিডব্লিউয়ের ক্ষেত্রেও হয়। বাম-স্থানান্তর কেন সুস্পষ্ট আউটপুট ক্রিয়াকলাপ হবে? কারণ আমরা যখন আমাদের প্রথম "হ্যালো, বিশ্ব" দেখি তখন আমরা সকলেই এটি সম্পর্কে শিখেছিলাম! আবেদন। এবং অন্য কোনও কারণে নয়।
এসবিআই

5
@ কুরিয়াসগুই: আপনার যদি এটি ব্যাখ্যা করতে হয় তবে তা স্পষ্টতই পরিষ্কার এবং বিতর্কিত নয়। তেমনি আপনার যদি ওভারলোডিং নিয়ে আলোচনা বা ডিফেন্সের প্রয়োজন হয়।
sbi

5
@ এসবিআই: "পিয়ার রিভিউ" সর্বদা একটি ভাল ধারণা। আমার কাছে খারাপভাবে চুজেন অপারেটরটি খারাপভাবে বেছে নেওয়া ফাংশন নামের চেয়ে আলাদা নয় (আমি অনেকগুলি দেখেছি)। অপারেটর কেবল ফাংশন। বেশিও না, কমও না. বিধি ঠিক একই। এবং একটি ধারণা ভাল কিনা তা বুঝতে, সবচেয়ে ভাল উপায়টি বোঝার জন্য এটি কতক্ষণ সময় নেয় তা বোঝা যায়। (অতএব, সমবয়সী পর্যালোচনা
অবশ্যম্ভাবী, তবে দোসর

5
@ এসবিআই আমার কাছে কেবলমাত্র একদম সুস্পষ্ট এবং অনিন্দ্য সত্য operator==এটি হ'ল এটি একটি সমতুল্য সম্পর্ক হওয়া উচিত (আইওডাব্লু, আপনার অ সিগন্যালিং এনএএন ব্যবহার করা উচিত নয়)। পাত্রে অনেক কার্যকর সমতুল্য সম্পর্ক রয়েছে। সাম্য বলতে কী বোঝায়? " aসমান b" এর অর্থ aএবং bএকই গাণিতিক মান রয়েছে। একটি (নন-এনএন) এর গাণিতিক মানের ধারণাটি floatস্পষ্ট, তবে একটি ধারকটির গাণিতিক মানের অনেকগুলি স্বতন্ত্র (টাইপ রিকারসিভ) দরকারী সংজ্ঞা থাকতে পারে। সাম্যের শক্তিশালী সংজ্ঞাটি "তারা একই জিনিস" এবং এটি অকেজো।
কৌতূহলী

265

সি ++ এ অপারেটর ওভারলোডিংয়ের সাধারণ সিনট্যাক্স

আপনি সি ++ তে অন্তর্নির্মিত প্রকারের জন্য অপারেটরের অর্থ পরিবর্তন করতে পারবেন না, অপারেটরগুলি কেবল ব্যবহারকারী-সংজ্ঞায়িত প্রকার 1 এর জন্য ওভারলোড করা যাবে । এটি হ'ল কমপক্ষে অপারেটরগুলির একটি ব্যবহারকারীর সংজ্ঞায়িত টাইপের হতে হবে। অন্যান্য ওভারলোডেড ফাংশনগুলির মতো, অপারেটরগুলি নির্দিষ্ট পরামিতিগুলির জন্য একবার মাত্র ওভারলোড করা যায়।

সমস্ত অপারেটর সি ++ এ ওভারলোড করা যাবে না। ওভারলোড করা যায় না এমন অপারেটরগুলির মধ্যে রয়েছে: . :: sizeof typeid .*এবং সি ++ এ একমাত্র টেরিনারি অপারেটর,?:

সি ++ তে ওভারলোড করা যায় এমন অপারেটরগুলির মধ্যে হ'ল:

  • পাটিগণিত অপারেটর: + - * / %এবং += -= *= /= %=(সমস্ত বাইনারি ইনফিক্স); + -(অ্যানারি উপসর্গ); ++ --(অ্যানারি উপসর্গ এবং পোস্টফিক্স)
  • বিট ম্যানিপুলেশন: & | ^ << >>এবং &= |= ^= <<= >>=(সমস্ত বাইনারি ইনফিক্স); ~(অ্যানারি উপসর্গ)
  • বুলিয়ান বীজগণিত: == != < > <= >= || &&(সমস্ত বাইনারি ইনফিক্স); !(অ্যানারি উপসর্গ)
  • স্মৃতি ব্যবস্থাপনা: new new[] delete delete[]
  • অন্তর্নিহিত রূপান্তর অপারেটরগুলি
  • বিবিধ: = [] -> ->* , (সমস্ত বাইনারি ইনফিক্স); * &(সমস্ত অ্যানারি উপসর্গ) ()(ফাংশন কল, এন-অ্যারি ইনফিক্স)

তবে, আপনি এই সমস্তগুলি ওভারলোড করতে পারবেন তার অর্থ এই নয় যে আপনার এটি করা উচিত । অপারেটর ওভারলোডিংয়ের প্রাথমিক নিয়মগুলি দেখুন।

সি ++ এ অপারেটরগুলি বিশেষ নামের সাথে ফাংশন আকারে ওভারলোড হয় । অন্যান্য ফাংশনের মতোই, ওভারলোডেড অপারেটরগুলি সাধারণত তাদের বাম অপারেন্ডের ধরণের সদস্য ফাংশন হিসাবে বা অ-সদস্য ফাংশন হিসাবে প্রয়োগ করা যেতে পারে । আপনি যে কোনও একটি বাছাই করতে বা স্বাধীন হতে বাধ্য তা বিভিন্ন মানদণ্ডের উপর নির্ভর করে। 2 একটি অ্যানারি অপারেটর @3 , একটি অবজেক্ট এক্স-এ প্রয়োগ করা হয়, হিসাবে operator@(x)বা হিসাবে আহ্বান জানানো হয় x.operator@()। একটি বাইনারি ইনফিক্স অপারেটর @, বস্তুগুলিতে প্রয়োগ হয় xএবং y, হয় operator@(x,y)বা হিসাবে বলা হয় x.operator@(y)4

অপারেটরগুলি যে সদস্যবিহীন ফাংশন হিসাবে প্রয়োগ করা হয় তারা কখনও কখনও তাদের অপারেন্ডের ধরণের বন্ধু হয়।

1 "ব্যবহারকারী-সংজ্ঞায়িত" শব্দটি কিছুটা বিভ্রান্তিকর হতে পারে। সি ++ বিল্ট-ইন টাইপ এবং ব্যবহারকারী-সংজ্ঞায়িত প্রকারের মধ্যে পার্থক্য তৈরি করে। প্রাক্তনগুলির জন্য উদাহরণস্বরূপ int, চর এবং দ্বিগুণ; পরবর্তীকালে সমস্ত স্ট্রাক্ট, শ্রেণি, ইউনিয়ন এবং এনাম প্রকারের অন্তর্ভুক্ত, এটি স্ট্যান্ডার্ড লাইব্রেরির অন্তর্ভুক্ত রয়েছে যদিও তারা ব্যবহারকারীর দ্বারা সংজ্ঞায়িত হয় না।

2 এটি এই FAQ এর পরবর্তী অংশে আচ্ছাদিত ।

3 সি একটি বৈধ অপারেটর ++, যে কারণে আমি একটি স্থানধারক হিসাবে এটি ব্যবহার করা হয়।@

4 সি ++ এ একমাত্র টেরিনারি অপারেটরকে ওভারলোড করা যায় না এবং কেবলমাত্র এন-আরি অপারেটরকে সর্বদা সদস্য ফাংশন হিসাবে প্রয়োগ করা উচিত।


সি ++ এ অপারেটর ওভারলোডিংয়ের তিনটি বেসিক বিধিগুলি অবিরত করুন ।


~অ্যানারি উপসর্গ, বাইনারি ইনফিক্স নয়।
mrkj

1
.*অ-ওভারলোডযোগ্য অপারেটরগুলির তালিকা থেকে অনুপস্থিত।
সেল্টিকিমিস্ট্রল

1
@ মাটেন আমি একটি প্রকৃত অপারেটরের পরিবর্তে একটি স্থানধারক ব্যবহার করতে চেয়েছিলাম যাতে এটি স্পেশাল অপারেটরের সম্পর্কে নয়, তবে তাদের সকলের জন্যই প্রযোজ্য। এবং, আপনি যদি সি ++ প্রোগ্রামার হতে চান তবে আপনার ছোট ছাপেও মনোযোগ দিতে শেখা উচিত। :)
এসবিআই

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

1
@ এসবিআই: আমি তিনটি প্রথম পোস্ট ইতিমধ্যে পড়েছি এবং এগুলি তৈরি করার জন্য আপনাকে ধন্যবাদ। :) আমি সমস্যার সমাধান করার চেষ্টা করব অন্যথায় আমি মনে করি যে এটি একটি পৃথক প্রশ্ন জিজ্ঞাসা করা ভাল। আমাদের জন্য জীবনকে এত সহজ করে তোলার জন্য আপনাকে আবারও ধন্যবাদ! : ডি
হোসেইন রহনামা

251

সদস্য এবং অ-সদস্যের মধ্যে সিদ্ধান্ত

বাইনারি অপারেটর =(অ্যাসাইনমেন্ট), [](অ্যারে সাবস্ক্রিপশন), ->(সদস্য অ্যাক্সেস) পাশাপাশি এন-অ্যারি ()(ফাংশন কল) অপারেটরকে সর্বদা সদস্য ফাংশন হিসাবে প্রয়োগ করা উচিত , কারণ ভাষার বাক্য গঠনটি তাদের প্রয়োজন।

অন্যান্য অপারেটরগুলি হয় সদস্য হিসাবে বা অ-সদস্য হিসাবে প্রয়োগ করা যেতে পারে। তাদের মধ্যে কিছু অবশ্য সাধারণত সদস্যহীন ফাংশন হিসাবে প্রয়োগ করতে হয়, কারণ তাদের বাম অপারেন্ডটি আপনার দ্বারা পরিবর্তন করা যায় না। এর মধ্যে সর্বাধিক বিশিষ্ট হলেন ইনপুট এবং আউটপুট অপারেটর <<এবং >>, যার বাম অপারেশনগুলি স্ট্যান্ডার্ড ক্লাসগুলি স্ট্যান্ডার্ড পাঠাগার থেকে যা আপনি পরিবর্তন করতে পারবেন না।

সমস্ত অপারেটরদের যেখানে আপনাকে সদস্য ফাংশন বা অ-সদস্য ফাংশন হিসাবে এগুলি প্রয়োগ করতে হবে, সিদ্ধান্ত নিতে নীচের নীচের নিয়মগুলি ব্যবহার করুন :

  1. যদি এটি অ্যানারি অপারেটর হয় তবে এটি সদস্য ফাংশন হিসাবে প্রয়োগ করুন ।
  2. যদি কোনও বাইনারি অপারেটর উভয় অপারেন্ডকে সমানভাবে আচরণ করে (এটি তাদের অপরিবর্তিত রাখে), এই অপারেটরটিকে একটি সদস্যবিহীন ফাংশন হিসাবে প্রয়োগ করুন ।
  3. বাইনারি অপারেটর যদি উভয় অপারেন্ডকে সমানভাবে চিকিত্সা না করে (সাধারণত এটি তার বাম অপারেন্ডকে পরিবর্তন করবে), অপারেন্ডের ব্যক্তিগত অংশগুলি অ্যাক্সেস করতে হলে এটি তার বাম অপারেন্ডের ধরণের সদস্য ফাংশন হিসাবে ব্যবহার করা কার্যকর হতে পারে ।

অবশ্যই, থাম্বের সমস্ত নিয়মের মতো, ব্যতিক্রম রয়েছে। আপনার যদি টাইপ থাকে

enum Month {Jan, Feb, ..., Nov, Dec}

এবং আপনি এর জন্য ইনক্রিমেন্ট এবং হ্রাস অপারেটরগুলি ওভারলোড করতে চান, আপনি সদস্য ফাংশন হিসাবে এটি করতে পারবেন না, যেহেতু সি ++ এ এনাম ধরণের সদস্য ফাংশন থাকতে পারে না। সুতরাং আপনাকে এটি একটি ফাংশন হিসাবে ওভারলোড করতে হবে। এবং operator<()শ্রেণীর টেমপ্লেটের জন্য শ্রেণীর টেমপ্লেটের অভ্যন্তরে বাসা বাঁধার জন্য ক্লাস সংজ্ঞাতে সদস্য ফাংশন ইনলাইন হিসাবে করা এবং লেখা পড়া অনেক সহজ। তবে এগুলি সত্যিই বিরল ব্যতিক্রম।

(তবে যদি আপনি একটি ব্যতিক্রম করতে, ইস্যু ভুলবেন না constপ্রতীক যে, সদস্য কাজগুলির জন্য অন্তর্নিহিত হয়ে জন্য -ness thisযুক্তি। একটি অ-সদস্য ফাংশন হিসেবে অপারেটর হিসেবে তার বাম-সবচেয়ে যুক্তি গ্রহণ করা হবে যদি constরেফারেন্স , সদস্য ফাংশন হিসাবে একই অপারেটরের একটি রেফারেন্স constতৈরির শেষে থাকতে হবে ))*thisconst


সাধারণ লোকেদের ওভারলোড করতে চালিয়ে যান ।


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

8
@ পেয়ার্সবাল: কার্যকর সি ++ মায়ার দ্বারা, সি ++ কোডিং স্ট্যান্ডার্ড সাটার দ্বারা। কোনটি আপনি উল্লেখ করা হয়? যাইহোক, আমি operator+=()সদস্য না হয়ে , বলার ধারণাটি অপছন্দ করি । এটিতে তার বাম-হাতের ক্রিয়াকলাপটি পরিবর্তন করতে হবে, সুতরাং সংজ্ঞা অনুসারে এটিকে তার অভ্যন্তরের গভীরে খনন করতে হবে। এটিকে সদস্য না করে আপনি কী অর্জন করবেন?
এসবিআই

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

3
@ এসবিআই: ওফস, কার্যকর, ব্যতিক্রমী ... আমি এই নামগুলি মিশিয়ে আশ্চর্য হওয়ার কিছু নেই। যাইহোক লাভটি হ'ল কোনও অবজেক্টের ব্যক্তিগত / সুরক্ষিত ডেটাতে অ্যাক্সেস রয়েছে এমন ফাংশনের সংখ্যা যতটা সম্ভব সীমাবদ্ধ করা। এইভাবে, আপনি আপনার বর্গের এনক্যাপসুলেশন বাড়িয়েছেন, এটির রক্ষণাবেক্ষণ / পরীক্ষা / বিবর্তনকে সহজ করে তুলেছেন।
পারা্সেবল

12
@ এসবিআই: একটি উদাহরণ। ধরা যাক আপনি উভয় operator +=এবং appendপদ্ধতি দুটি সহ একটি স্ট্রিং ক্লাস কোডিং করছেন । appendপদ্ধতি সম্পূর্ণ, কারণ আপনি আমি সূচক এন -1 থেকে সূচি থেকে প্যারামিটারের একটি সাবস্ট্রিং সংযুক্ত করতে পারবেন: append(string, start, end)এটা আছে যৌক্তিক বলে মনে +=সহ কল পরিশেষে যোগ start = 0এবং end = string.size। এই মুহুর্তে, সংযোজন একটি সদস্য পদ্ধতি হতে পারে, তবে operator +=সদস্য হওয়ার দরকার নেই, এবং এটিকে সদস্যবিহীন করে তোলা স্ট্রিং অভ্যন্তরের সাথে কোড খেলার পরিমাণ হ্রাস পাবে, সুতরাং এটি খুব ভাল বিষয় .... ^ _ ^ ...
প্যাসেসারবাল

165

রূপান্তর অপারেটর (ব্যবহারকারী সংজ্ঞায়িত রূপান্তর হিসাবে পরিচিত)

সি ++ এ আপনি রূপান্তর অপারেটর, অপারেটর তৈরি করতে পারেন যা সংকলকটিকে আপনার প্রকার এবং অন্যান্য সংজ্ঞায়িত প্রকারের মধ্যে রূপান্তর করতে দেয়। দুটি ধরণের রূপান্তর অপারেটর রয়েছে, অন্তর্নিহিত এবং সুস্পষ্ট।

অন্তর্নিহিত রূপান্তর অপারেটরগুলি (সি ++ 98 / সি ++ 03 এবং সি ++ 11)

একটি অন্তর্নিহিত রূপান্তর অপারেটর সংকলকটিকে সুস্পষ্টভাবে রূপান্তর করতে দেয় (যেমন রূপান্তর রূপান্তর করে intএবং এর মধ্যে long) কোনও ব্যবহারকারী-সংজ্ঞায়িত টাইপের মান অন্য কোনও প্রকারে রূপান্তর করতে।

নীচে একটি অন্তর্ভুক্ত রূপান্তর অপারেটর সহ একটি সাধারণ বর্গ:

class my_string {
public:
  operator const char*() const {return data_;} // This is the conversion operator
private:
  const char* data_;
};

নিখুঁত রূপান্তর অপারেটরগুলি যেমন ওয়ান-আর্গুমেন্ট কনস্ট্রাক্টরগুলি হ'ল ব্যবহারকারী-সংজ্ঞায়িত রূপান্তর। অতিরিক্ত লোড ফাংশনে কোনও কল মিলানোর চেষ্টা করার সময় সংকলকগণ একজন ব্যবহারকারী-সংজ্ঞায়িত রূপান্তরকে মঞ্জুরি দেবেন।

void f(const char*);

my_string str;
f(str); // same as f( str.operator const char*() )

প্রথমে এটি খুব সহায়ক বলে মনে হচ্ছে তবে এর সাথে সমস্যাটি হ'ল অন্তর্নিহিত রূপান্তরটি এমনকি যখন কাক্সিক্ষত হয় না তখনও লাথি দেয়। নিম্নলিখিত কোড ইন, void f(const char*)কারণ বলা হবে my_string()একটি নয় lvalue , তাই প্রথম মিলছে না:

void f(my_string&);
void f(const char*);

f(my_string());

প্রাথমিকভাবে সহজেই এই ভুলটি পাওয়া যায় এবং এমনকি অভিজ্ঞ সি ++ প্রোগ্রামাররা মাঝে মাঝে অবাক হন কারণ সংকলক একটি ওভারলোড চয়ন করে যা তারা সন্দেহ করেনি। এই সমস্যাগুলি সুস্পষ্ট রূপান্তর অপারেটর দ্বারা প্রশমিত করা যেতে পারে।

সুস্পষ্ট রূপান্তর অপারেটর (সি ++ 11)

অন্তর্নিহিত রূপান্তর অপারেটরগুলির বিপরীতে, সুস্পষ্ট রূপান্তর অপারেটররা কখনই এগুলি প্রত্যাশা করে না যখন আপনি তাদের কাছে প্রত্যাশা করবেন না। সুস্পষ্ট রূপান্তর অপারেটর সহ নিম্নলিখিতটি একটি সাধারণ শ্রেণি:

class my_string {
public:
  explicit operator const char*() const {return data_;}
private:
  const char* data_;
};

লক্ষ্য করুন explicit। এখন যখন আপনি অন্তর্ভুক্ত রূপান্তর অপারেটরগুলি থেকে অপ্রত্যাশিত কোডটি কার্যকর করার চেষ্টা করেন, আপনি একটি সংকলক ত্রুটি পাবেন:

prog.cpp: ফাংশনে 'int main ()':
prog.cpp: 15: 18: ত্রুটি: 'f (my_string)' এ কল করার জন্য কোনও মিল নেই
prog.cpp: 15: 18: দ্রষ্টব্য: প্রার্থীরা হলেন:
prog.cpp: 11: 10: দ্রষ্টব্য: অকার্যকর চ (my_string এবং)
prog.cpp: 11: 10: দ্রষ্টব্য: 'মাই_স্ট্রিং' থেকে 'মাই_স্ট্রিং &' তে আর্গুমেন্টের জন্য কোনও রূপান্তর নেই
prog.cpp: 12: 10: দ্রষ্টব্য: অকার্যকর এফ (কনস্টিক চর *)
prog.cpp: 12: 10: দ্রষ্টব্য: 'মাই_স্ট্রিং' থেকে 'কনস্টের চর' তে আর্গুমেন্টের জন্য কোনও রূপান্তর নেই

সুস্পষ্ট কাস্ট অপারেটরকে অনুরোধ করতে, আপনাকে static_castসি-স্টাইলের castালাই বা কনস্ট্রাক্টর স্টাইলের castালাই (যেমন T(value)) ব্যবহার করতে হবে।

যাইহোক, এটির একটি ব্যতিক্রম রয়েছে: সংকলককে সুস্পষ্টভাবে রূপান্তর করার অনুমতি দেওয়া হয়েছে bool। তদ্ব্যতীত, সংকলকটি রূপান্তরিত হওয়ার পরে আর একটি অন্তর্নিহিত রূপান্তর করার অনুমতি দেয় না bool(একটি সংকলককে একবারে 2 টি অন্তর্ভুক্ত রূপান্তর করার অনুমতি দেওয়া হয় তবে সর্বোচ্চ 1 টি ব্যবহারকারী-সংজ্ঞায়িত রূপান্তর)।

সংকলক "অতীত" castালাই করবে না bool, সুস্পষ্ট রূপান্তর অপারেটররা এখন সেফ বুল আইডিয়মের প্রয়োজনীয়তা সরিয়ে ফেলবে । উদাহরণস্বরূপ, সি ++ 11 এর আগে স্মার্ট পয়েন্টারগুলি ইন্টিগ্রাল ধরণের রূপান্তরগুলি রোধ করতে সেফ বুল আইডিয়ম ব্যবহার করেছিল। সি ++ ১১-এ, স্মার্ট পয়েন্টারগুলির পরিবর্তে একটি স্পষ্টতাল অপারেটর ব্যবহার করা হয় কারণ সংকলক স্পষ্টতই কোনও ধরণের রূপকে রূপে রূপান্তরিত করার পরে স্পষ্টতই একটি অবিচ্ছেদ্য ধরণের রূপান্তরিত করার অনুমতি দেয় না।

ওভারলোডিং newএবং এdelete চালিয়ে যান ।


148

ওভারলোডিং newএবংdelete

নোট: সঙ্গে এটি কেবলমাত্র পুলিশ সিনট্যাক্স ওভারলোডিং এরnewএবংdeleteসঙ্গে না বাস্তবায়ন যেমন ওভারলোড অপারেটরদের। আমি মনে করি যে ওভারলোডিং এর শব্দার্থবিদ্যাnew এবং deleteতাদের নিজস্ব প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী প্রাপ্য ওভারলোডিং আমি এটি ন্যায়বিচার করবেন না করতে পারেন, অপারেটর বিষয় মধ্যে।

বুনিয়াদি

সি ++ এ আপনি যখন নতুন এক্সপ্রেশন লেখেন তখন new T(arg)দুটি বিষয়ের মতো হয় যখন এই অভিব্যক্তিটি মূল্যায়ন করা হয়: প্রথমে operator newকাঁচা স্মৃতি পেতে আহ্বান জানানো হয়, এবং তারপরে উপযুক্ত কন্সট্রাক্টরকে Tএই কাঁচা স্মৃতিটিকে একটি বৈধ অবজেক্টে পরিণত করার জন্য অনুরোধ করা হয়। তেমনি, আপনি যখন কোনও বস্তু মুছবেন, প্রথমে তার ধ্বংসকারীকে ডেকে আনা হবে এবং তারপরে স্মৃতিতে ফিরে আসে operator delete
সি ++ আপনাকে এই দুটি ক্রিয়াকলাপ টিউন করতে দেয়: মেমরি পরিচালনা এবং বরাদ্দ মেমরির মধ্যে অবজেক্টটির নির্মাণ / বিন্যাস। পরবর্তীটি কোনও শ্রেণীর জন্য কনস্ট্রাক্টর এবং ডেস্ট্রাক্টর লিখে কাজটি সম্পন্ন করা হয়। ফাইন টিউনিং মেমরি ম্যানেজমেন্ট আপনার নিজের operator newএবং এর মাধ্যমে লেখা হয় operator delete

অপারেটর ওভারলোডিংয়ের প্রাথমিক নিয়মের প্রথমটি - এটি করবেন না - বিশেষত ওভারলোডিং newএবং এর ক্ষেত্রে প্রযোজ্য delete। এই অপারেটরগুলিকে ওভারলোড করার প্রায় একমাত্র কারণগুলি হল পারফরম্যান্স সমস্যা এবং মেমরির সীমাবদ্ধতা এবং অনেক ক্ষেত্রে, ব্যবহৃত অন্যান্য অ্যালগরিদমে পরিবর্তনগুলির মতো অন্যান্য ক্রিয়াগুলি মেমরি পরিচালনার সাম্প্রতিক চেষ্টা করার চেয়ে অনেক বেশি দাম / লাভ অনুপাত সরবরাহ করবে

সি ++ স্ট্যান্ডার্ড লাইব্রেরিতে পূর্বনির্ধারিত newএবং deleteঅপারেটরগুলির একটি সেট আসে । সর্বাধিক গুরুত্বপূর্ণগুলি হ'ল:

void* operator new(std::size_t) throw(std::bad_alloc); 
void  operator delete(void*) throw(); 
void* operator new[](std::size_t) throw(std::bad_alloc); 
void  operator delete[](void*) throw(); 

প্রথম দুটি বস্তুর জন্য মেমরি বরাদ্দ / ডিলোকট স্মৃতি, পরের দুটি বস্তুর অ্যারের জন্য। আপনি যদি এর নিজস্ব সংস্করণগুলি সরবরাহ করেন তবে সেগুলি ওভারলোড হবে না, তবে মানক গ্রন্থাগার থেকে এগুলি প্রতিস্থাপন করবে।
আপনি যদি ওভারলোড করেন তবে আপনার কলটি করার ইচ্ছা কখনও না থাকলেও আপনার operator newম্যাচটি সর্বদা ওভারলোড করা উচিত operator delete। কারণ, একটি কন্সট্রাকটর একটি নতুন মত প্রকাশের মূল্যায়নের সময় ছোঁড়ার যদি, রান-টাইম সিস্টেম মেমরি আসতে হবে operator deleteমিলে operator newযে বস্তুর তৈরি করতে মেমরি বরাদ্দ করা ডাকা হয়। আপনি যদি একটি ম্যাচিং সরবরাহ না করেন তাহলে operator delete, ডিফল্টটিকে বলা হয়, যা প্রায় সর্বদা ভুল।
আপনি যদি ওভারলোড করেন newএবং delete, আপনারও অ্যারে ভেরিয়েন্টগুলি ওভারলোডিংয়ের বিষয়টি বিবেচনা করা উচিত।

স্থাননির্ণয় new

সি ++ নতুন এবং মুছুন অপারেটরদের অতিরিক্ত যুক্তি নিতে অনুমতি দেয়।
তথাকথিত প্লেসমেন্ট নতুন আপনাকে নির্দিষ্ট ঠিকানায় একটি অবজেক্ট তৈরি করতে দেয় যা এতে পাস করা হয়:

class X { /* ... */ };
char buffer[ sizeof(X) ];
void f()
{ 
  X* p = new(buffer) X(/*...*/);
  // ... 
  p->~X(); // call destructor 
} 

স্ট্যান্ডার্ড লাইব্রেরি নতুন এবং মুছে ফেলা অপারেটরগুলির উপযুক্ত ওভারলোডগুলি নিয়ে আসে:

void* operator new(std::size_t,void* p) throw(std::bad_alloc); 
void  operator delete(void* p,void*) throw(); 
void* operator new[](std::size_t,void* p) throw(std::bad_alloc); 
void  operator delete[](void* p,void*) throw(); 

নোট করুন, উপরে বর্ণিত নতুন প্লেসমেন্টের উদাহরণ কোডে operator deleteকখনই ডাকা হয় না, যদি না এক্স এর নির্মাণকারী ব্যতিক্রম ছুঁড়ে না ফেলে।

আপনি ওভারলোড newএবং deleteঅন্যান্য যুক্তি দিয়েও করতে পারেন । নতুন স্থাপনার জন্য অতিরিক্ত যুক্তি হিসাবে, এই যুক্তিগুলি কীওয়ার্ডের পরে বন্ধনীগুলির মধ্যেও তালিকাভুক্ত করা হয় new। কেবলমাত্র historicalতিহাসিক কারণে, এ জাতীয় রূপগুলি প্রায়শই প্লেসমেন্টকে নতুন বলা হয়, এমনকি যদি তাদের যুক্তি কোনও নির্দিষ্ট ঠিকানায় কোনও বস্তু স্থাপনের জন্য না হয়।

ক্লাস-নির্দিষ্ট নতুন এবং মুছুন

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

class my_class { 
  public: 
    // ... 
    void* operator new();
    void  operator delete(void*,std::size_t);
    void* operator new[](size_t);
    void  operator delete[](void*,std::size_t);
    // ... 
}; 

অতিরিক্ত লোড এইভাবে, নতুন এবং মুছা স্থির সদস্য ফাংশনগুলির মতো আচরণ করে। এর বস্তুর জন্য my_class, std::size_tযুক্তি সর্বদা থাকবে sizeof(my_class)। যাইহোক, এই অপারেটরগুলি থেকে উদ্ভূত শ্রেণীর গতিযুক্ত বরাদ্দকৃত অবজেক্টগুলির জন্যও বলা হয়, এক্ষেত্রে এটি এর চেয়ে বেশি হতে পারে।

গ্লোবাল নতুন এবং মুছুন

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


11
আমি এটিও সম্মত নই যে গ্লোবাল অপারেটরকে নতুন এবং মুছে ফেলা প্রতিস্থাপন করা সাধারণত পারফরম্যান্সের জন্য: বিপরীতে, এটি সাধারণত বাগ ট্রেসিংয়ের জন্য।
Yttrill

1
আপনার এও লক্ষ্য করা উচিত, আপনি যদি ওভারলোডেড নতুন অপারেটর ব্যবহার করেন তবে আপনার মিলে যাওয়া যুক্তিগুলির সাথে একটি মোছা অপারেটর সরবরাহ করতে হবে। আপনি বলছেন যে বৈশ্বিক নতুন / মুছে ফেলা বিভাগে যেখানে এটি খুব বেশি আগ্রহের নয়।
Yttrill

13
@ আপনি এখনও বিভ্রান্তিকর জিনিস অর্থ ওভারলোড পায়। "অপারেটর ওভারলোডিং" এর অর্থ হ'ল বোঝা load এর অর্থ এই নয় যে আক্ষরিক ক্রিয়াকলাপগুলি অতিরিক্ত লোড হয়েছে এবং বিশেষত অপারেটরে নতুন স্ট্যান্ডার্ডের সংস্করণটি ওভারলোড করবে না। @ এসবিআই বিপরীতে দাবি করে না। একে "ওভারলোডিং অ্যাডে অপারেটর" বলা সাধারণ বলে একে "ওভারলোডিং নতুন" বলা সাধারণ common
জোহানেস স্কাউব -

1
@ এসবিআই: দেখুন (বা আরও উন্নত লিঙ্ক করুন) getw.ca/publications/mill15.htm । কখনও কখনও nothrowনতুন ব্যবহার করে এমন লোকদের প্রতি এটি কেবল ভাল অনুশীলন ।
আলেকজান্দ্রি সি

1
"আপনি যদি কোনও ম্যাচিং অপারেটর মোছার ব্যবস্থা না করেন, তবে ডিফল্টটিকে বলা হয়" -> আসলে, আপনি যদি কোনও যুক্তি যুক্ত করেন এবং কোনও মিলে মুছতে তৈরি না করেন, কোনও অপারেটর মুছুন একেবারেই বলা হয় না এবং আপনার একটি স্মৃতি ফাঁস হয়। (১৫.২.২, অবজেক্টের দ্বারা দখলকৃত স্টোরেজটি কেবলমাত্র যদি উপযুক্ত ... অপারেটর মোছার সন্ধান পাওয়া যায় তবে
অবনতি হয়

46

operator<<স্ট্রিমিং অবজেক্টের জন্য std::coutবা কোনও ফাইলে সদস্য ফাংশন হতে পারে না কেন ?

আসুন বলি আপনার কাছে রয়েছে:

struct Foo
{
   int a;
   double b;

   std::ostream& operator<<(std::ostream& out) const
   {
      return out << a << " " << b;
   }
};

যে দেওয়া, আপনি ব্যবহার করতে পারবেন না:

Foo f = {10, 20.0};
std::cout << f;

যেহেতু এর operator<<সদস্য ফাংশন হিসাবে ওভারলোড করা হয়েছে Foo, অপারেটরের এলএইচএস অবশ্যই একটি Fooবস্তু হতে হবে । যার অর্থ, আপনাকে ব্যবহার করতে হবে:

Foo f = {10, 20.0};
f << std::cout

যা খুব স্বজ্ঞাত।

আপনি যদি এটি অ-সদস্য ফাংশন হিসাবে সংজ্ঞায়িত করেন,

struct Foo
{
   int a;
   double b;
};

std::ostream& operator<<(std::ostream& out, Foo const& f)
{
   return out << f.a << " " << f.b;
}

আপনি ব্যবহার করতে সক্ষম হবেন:

Foo f = {10, 20.0};
std::cout << f;

যা খুব স্বজ্ঞাত।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.