সি ++ তে একই শ্রেণীর জন্য বিভিন্ন ধরণের কীভাবে সংজ্ঞা দেওয়া যায়


84

আমি একাধিক প্রকারের একই রূপায়ণ ভাগ করে নিতে চাই তবে এখনও সি ++ এ বিভিন্ন ধরণের।

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

class Apple {
     int p;
public:
     Apple (int p) : p(p) {}
     int price () const {return p;}
}

class Banana {
     int p;
public:
     Banana (int p) : p(p) {}
     int price () const {return p;}
}

class Orange ...

কোডটি সদৃশ না করার জন্য, দেখে মনে হচ্ছে আমি একটি বেস শ্রেণি ফল ব্যবহার করতে পারি এবং এর থেকে উত্তরাধিকারী হতে পারি:

class Fruit {
     int p;
public:
     Fruit (int p) : p(p) {}
     int price () const {return p;}
}

class Apple: public Fruit {};
class Banana: public Fruit {};
class Orange: public Fruit {};

তবে তারপরে, কনস্ট্রাক্টররা উত্তরাধিকার সূত্রে প্রাপ্ত হয় না এবং তাদের পুনরায় লিখতে হয়।

এমন কোনও ব্যবস্থা আছে (টাইপডেফস, টেমপ্লেটস, উত্তরাধিকার ...) যা আমাকে সহজেই বিভিন্ন ধরণের সমান শ্রেণিতে থাকতে দেয়?


আপনি কেন এটার দরকার পড়বেন আরও বিশদ দিয়ে বলতে পারেন? আমি কোন ভাল ধারণা নিয়ে আসতে পারি না। যদি ক্লাসগুলি বাস্তবায়ন ভাগ করে দেয়, তার অর্থ কি তারা কার্যকারিতা ভাগ করে না?
jnovacho

4
হ্যাঁ, তবে যেহেতু তাদের বিভিন্ন ধরণের থাকবে তাই সংকলনের সময় কিছু প্রোগ্রামিং ত্রুটি সনাক্ত করা যায় (উদাহরণস্বরূপ, আপেল এবং কমলাগুলি মার্জ করা)।
anumi

উত্তর:


119

একটি সাধারণ কৌশলটি এমন একটি শ্রেণিবদ্ধ টেমপ্লেট থাকে যেখানে টেমপ্লেট আর্গুমেন্টটি অনন্য প্রকারে পরিণত করতে কেবল অনন্য টোকেন ("ট্যাগ") হিসাবে কাজ করে:

template <typename Tag>
class Fruit {
    int p;
public:
    Fruit(int p) : p(p) { }
    int price() const { return p; }
};

using Apple = Fruit<struct AppleTag>;
using Banana = Fruit<struct BananaTag>;

নোট করুন যে ট্যাগ ক্লাসগুলি এমনকি সংজ্ঞায়িত করার প্রয়োজন নেই, এটি একটি অনন্য প্রকারের নাম ঘোষণার জন্য যথেষ্ট । এটি কাজ করে কারণ ট্যাগটি বাস্তবে টেমপ্লেটের যে কোনও জায়গায় ব্যবহৃত হয় । এবং আপনি টেমপ্লেট আর্গুমেন্ট তালিকার ভিতরে টাইপটির নামটি ঘোষণা করতে পারেন (@ Xeo এ টুপি টিপ)।

usingসিনট্যাক্স সি ++ 11 হয়। আপনি যদি C ++ 03 এর সাথে আটকে থাকেন তবে পরিবর্তে এটি লিখুন:

typedef Fruit<struct AppleTag> Apple;

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

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

// Actual `Fruit` class remains unchanged, except for template declaration
template <typename Tag, typename = Tag>
class Fruit { /* unchanged */ };

template <typename T>
class Fruit<T, T> : public Fruit<T, void> {
public:
    // Should work but doesn’t on my compiler:
    //using Fruit<T, void>::Fruit;
    Fruit(int p) : Fruit<T, void>(p) { }
};

using Apple = Fruit<struct AppleTag>;
using Banana = Fruit<struct BananaTag>;

+1, আপনি পৃথক ফলের জন্য কোনও অতিরিক্ত সম্পত্তি সংজ্ঞায়িত করতে না চাইলে আমি এই সাথে যাব ...
নিম

20
আপনি আসলে শুধু তাদের টেমপ্লেট আর্গুমেন্ট তালিকার, যা আমি চমত্কার সুবিধাজনক এটি ভিতরে ঘোষণা করতে পারেন: Fruit<struct SomeTag>
জিও

4
@ কনরাড রুডলফ এটি লজ্জাজনক আমি সম্পাদনা নিজেই +1 করতে পারি না ..... আমি এই মন্তব্যটি সম্পাদনা দেখেছি ।
চিরকালীন

4
@ আন্তঃমেট এলএল - আমি কখনই ভাবিনি যে কেউ এটি দেখতে পাবে। তবে ভাল, কেউ না তাকালেও আপনাকে মজার হতে হবে। ;-)
কনরাড রুডল্ফ

4
এর একটি নেতিবাচক দিক হ'ল বিভিন্ন ধরণের জন্য টেম্পলেট ইনস্ট্যান্টেশনের একাধিক নির্গমন। এই নকলগুলি ব্যাপকভাবে ব্যবহৃত লঙ্কারগুলি দ্বারা মুছে ফেলা হয়েছে?
বালক

19

টেমপ্লেটগুলি ব্যবহার করুন এবং ফলমূল হিসাবে একটি বৈশিষ্ট্য ব্যবহার করুন :

struct AppleTraits
{
  // define apple specific traits (say, static methods, types etc)
  static int colour = 0; 
};

struct OrangeTraits
{
  // define orange specific traits (say, static methods, types etc)
  static int colour = 1; 
};

// etc

তারপরে একটি একক Fruitশ্রেণি রয়েছে যা এই বৈশিষ্ট্যটিতে টাইপ করা হয়।

template <typename FruitTrait>
struct Fruit
{
  // All fruit methods...
  // Here return the colour from the traits class..
  int colour() const
  { return FruitTrait::colour; }
};

// Now use a few typedefs
typedef Fruit<AppleTraits> Apple;
typedef Fruit<OrangeTraits> Orange;

কিছুটা ওভারকিল হতে পারে! ;)


14

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