যেমনটি লেখা আছে, এটি "গন্ধ পেয়েছে", তবে এটি সম্ভবত আপনি যে উদাহরণ দিয়েছেন। জেনেরিক বস্তুর পাত্রে ডেটা সঞ্চয় করার, তারপর ভোটদান এটা ডেটাতে অ্যাক্সেস পেতে হয় না স্বয়ংক্রিয়ভাবে কোড গন্ধ। আপনি এটি দেখতে পাবেন অনেক পরিস্থিতিতে। যাইহোক, আপনি যখন এটি ব্যবহার করেন, আপনি কী করছেন, কীভাবে করছেন এবং কেন করছেন সে সম্পর্কে আপনার সচেতন হওয়া উচিত। আমি উদাহরণটি যখন দেখি, তখন স্ট্রিং ভিত্তিক তুলনা ব্যবহারটি আমাকে জানাতে কোন বস্তুটি এমন জিনিস যা আমার ব্যক্তিগত গন্ধ মিটারকে ট্রিপ করে। এটি প্রস্তাব দেয় যে আপনি এখানে কী করছেন তা পুরোপুরি নিশ্চিত নন (যা ভাল, যেহেতু আপনার এখানে প্রোগ্রামারদের কাছে আসার বুদ্ধি ছিল SE এসই বলুন "আরে, আমি মনে করি না আমি যা করছি তা পছন্দ করি, সহায়তা করুন আমার বাইরে! ")।
এর মতো জেনেরিক পাত্রে ডেটা ingালার প্যাটার্নের সাথে মৌলিক সমস্যাটি হ'ল ডেটা প্রযোজক এবং ডেটা গ্রাহককে অবশ্যই একসাথে কাজ করতে হবে, তবে এটি প্রথম নজরে তারা তা করেছে তা স্পষ্ট নয়। এই প্যাটার্নের প্রতিটি উদাহরণে, দুর্গন্ধযুক্ত বা দুর্গন্ধযুক্ত নয়, এটি মৌলিক বিষয়। পরবর্তী বিকাশকারীটির পক্ষে সম্পূর্ণ অজানা থাকা খুব সম্ভব যে আপনি এই প্যাটার্নটিটি করছেন এবং এটি দুর্ঘটনাক্রমে ভেঙে দিয়েছেন, সুতরাং আপনি যদি এই প্যাটার্নটি ব্যবহার করেন তবে আপনাকে অবশ্যই পরবর্তী বিকাশকারীকে সাহায্য করার জন্য যত্নবান হতে হবে। আপনার অবিচ্ছিন্নভাবে কোডটি না ভাঙতে আপনার পক্ষে আরও সহজ করে তুলতে হবে কিছু বিশদের কারণে যার অস্তিত্ব নেই।
উদাহরণস্বরূপ, আমি যদি কোনও খেলোয়াড়ের অনুলিপি করতে চাই? আমি যদি কেবল প্লেয়ার অবজেক্টের বিষয়বস্তুগুলি দেখি তবে এটি বেশ সহজ দেখাচ্ছে looks আমি শুধু কপি আছে attack
, defense
এবং tools
ভেরিয়েবল। পাই হিসাবে সহজ! ঠিক আছে, আমি দ্রুত জানতে পারব যে আপনার পয়েন্টারগুলির ব্যবহার এটি আরও শক্ত করে তোলে (কোনও এক সময়ে এটি স্মার্ট পয়েন্টারগুলির দিকে নজর দেওয়া ভাল তবে এটি অন্য বিষয়)। যে সহজে সমাধান করা হয়। আমি কেবল প্রতিটি সরঞ্জামের নতুন কপি তৈরি করব এবং সেগুলি আমার নতুন tools
তালিকায় রাখব । সর্বোপরি, Tool
কেবলমাত্র একজন সদস্য সহ সত্যই সাধারণ শ্রেণি। সুতরাং আমি একটি অনুলিপি তৈরি করেছি Sword
, এর একটি অনুলিপি সহ , তবে আমি জানতাম না যে এটি একটি তরোয়াল ছিল, তাই আমি কেবলমাত্র অনুলিপি করেছি name
। পরে, attack()
ফাংশনটি নামটি দেখে, এটি একটি "তরোয়াল" দেখেছে, এটি কাস্ট করে এবং খারাপ জিনিস ঘটে!
আমরা এই কেসটিকে সকেট প্রোগ্রামিংয়ের অন্য কেসের সাথে তুলনা করতে পারি, যা একই প্যাটার্নটি ব্যবহার করে। আমি এইভাবে একটি ইউনিক্স সকেট ফাংশন সেট আপ করতে পারি:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
serv_addr.sin_addr.s_addr = INADDR_ANY;
bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
কেন এটি একই প্যাটার্ন? যেহেতু bind
একটি গ্রহণ করে না sockaddr_in*
, এটি আরও জেনেরিক গ্রহণ করে sockaddr*
। আপনি যদি এই ক্লাসগুলির সংজ্ঞাটি দেখেন তবে আমরা দেখতে পাই যে আমাদের যে sockaddr
পরিবারকে sin_family
* অর্পণ করা হয়েছে তার কেবলমাত্র একজন সদস্য রয়েছেন । পরিবারটি বলে যে কোন উপ টাইপটি আপনার করা উচিত sockaddr
। AF_INET
আপনাকে বলে যে ঠিকানা কাঠামো আসলে একটি sockaddr_in
। যদি এটি হয় AF_INET6
তবে ঠিকানাটি একটি হবে sockaddr_in6
, যার বৃহত্তর IPv6 ঠিকানাগুলিকে সমর্থন করার জন্য বৃহত্তর ক্ষেত্র রয়েছে।
এটি আপনার Tool
উদাহরণের সাথে সমান , এটি কোনও পরিবারের পরিবর্তে কোন পরিবার নির্দিষ্ট করার জন্য কোনও পূর্ণসংখ্যা ব্যবহার করে std::string
। যাইহোক, আমি দাবি করছি যে এটি গন্ধযুক্ত নয়, এবং এটি "সকেটগুলি করার একটি স্ট্যান্ডার্ড উপায়, সুতরাং এটি 'গন্ধ পাওয়া উচিত নয়' ব্যতীত অন্য কারণে এটি করার চেষ্টা করুন, অবশ্যই এটি একই প্যাটার্ন, যা আমি কেন দাবি করি যে জেনেরিক বস্তুগুলিতে ডেটা সংরক্ষণ এবং এটি ingালাই স্বয়ংক্রিয়ভাবে কোড গন্ধ নয়, তবে তারা কীভাবে এটি ব্যবহার করে তাতে কিছুটা পার্থক্য রয়েছে যা এটি নিরাপদ করে তোলে।
এই নিদর্শনটি ব্যবহার করার সময়, সর্বাধিক গুরুত্বপূর্ণ তথ্য হ'ল উত্পাদক থেকে গ্রাহক পর্যন্ত সাবক্লাস সম্পর্কিত তথ্য পৌঁছে দেওয়া। আপনি name
মাঠের সাথে এটি করছেন এবং ইউনিক্স সকেটগুলি তাদের sin_family
ক্ষেত্রের সাথে কি করছেন । সেই ক্ষেত্রটি হ'ল সেই তথ্য যা ভোক্তাকে বুঝতে হবে যে প্রযোজক আসলে কী তৈরি করেছিলেন। এই ধরণের সমস্ত ক্ষেত্রে, এটি একটি গণনা হওয়া উচিত (বা খুব কমপক্ষে, একটি পূর্ণসংখ্যার একটি গণনার মতো অভিনয় করা)) কেন? আপনার গ্রাহক তথ্যটি কী করতে চলেছেন তা ভেবে দেখুন। তারা কিছু বড় if
বিবৃতি বা ক লিখেছেন প্রয়োজন হবেswitch
বিবৃতি, যেমনটি আপনি করেছেন, যেখানে তারা সঠিক উপপ্রকারটি নির্ধারণ করে, এটি ফেলে দেয় এবং ডেটা ব্যবহার করে। সংজ্ঞা অনুসারে, এই ধরণের কয়েকটি সংখ্যকই হতে পারে। আপনি এটির মতো স্ট্রিংয়ে সংরক্ষণ করতে পারেন তবে এর অনেক অসুবিধা রয়েছে:
- ধীর -
std::string
সাধারণত স্ট্রিং রাখতে কিছু গতিশীল মেমরি করতে হয়। প্রতিবার আপনার কী সাবক্লাস রয়েছে তা বের করতে চাইলে নামের সাথে মেলে তুলতে আপনাকে একটি সম্পূর্ণ পাঠ্য তুলনা করতে হবে।
- খুব বহুমুখী - যখন আপনি অত্যন্ত বিপজ্জনক কিছু করছেন তখন নিজেকে বাধা দেওয়ার জন্য কিছু বলার আছে। আমি এর মতো সিস্টেম পেয়েছি যা এটি কোন ধরণের অবজেক্টের দিকে চেয়েছিল তা জানাতে একটি স্ট্রিংয়ের সন্ধান করেছিল। কোনও অবজেক্টের নাম দুর্ঘটনাক্রমে সেই সাবস্ট্রিংটি উপস্থিত না হওয়া পর্যন্ত এটি দুর্দান্ত কাজ করেছে এবং মারাত্মক ক্রিপ্টিক ত্রুটি তৈরি করেছে। যেহেতু, যেমন আমরা উপরে বলেছি, আমাদের কেবল কয়েকটি সংখ্যক কেস প্রয়োজন, স্ট্রিংয়ের মতো বৃহত্তর বিদ্যুতের সরঞ্জাম ব্যবহার করার কোনও কারণ নেই। এটাও বিশালাকার...
- ত্রুটির প্রবণতা - আসুন কেবলমাত্র এটি বলে দিন যে কোনও গ্রাহক ঘটনাক্রমে কোনও যাদু কাপড়ের নাম স্থাপন করলে জিনিস কেন কাজ করছে না তা ডিবাগ করার চেষ্টা করে আপনি একটি হত্যাকারী ছটফট করতে যেতে চাইবেন
MagicC1oth
। সিরিয়াসলি, এর মতো বাগগুলি কী ঘটেছে তা বুঝতে পেরে মাথা ফাটিয়ে কয়েক দিন সময় নিতে পারে।
একটি গণনা অনেক ভাল কাজ করে। এটি দ্রুত, সস্তা এবং ত্রুটিযুক্ত প্রবণতা:
class Tool {
public:
enum TypeE {
kSword,
kShield,
kMagicCloth
};
TypeE type;
std::string typeName() const {
switch(type) {
case kSword: return "Sword";
case kSheild: return "Sheild";
case kMagicCloth: return "Magic Cloth";
default:
throw std::runtime_error("Invalid enum!");
}
}
};
এই উদাহরণটি switch
enums জড়িত একটি বিবৃতিও দেখায় , এই প্যাটার্নের একক সবচেয়ে গুরুত্বপূর্ণ অংশটি: এমন একটি default
মামলা যা ছুড়ে ফেলে। আপনি যদি নিখুঁতভাবে কাজগুলি করেন তবে আপনার কখনই সেই পরিস্থিতিতে পড়া উচিত নয় । তবে, যদি কেউ একটি নতুন সরঞ্জাম প্রকার যুক্ত করে এবং আপনি এটি সমর্থন করার জন্য আপনার কোডটি আপডেট করতে ভুলে যান তবে আপনি ত্রুটিটি ধরার জন্য কিছু চাইবেন। আসলে, আমি তাদের এতটাই সুপারিশ করছি যে আপনার প্রয়োজন না হলেও আপনার এগুলি যুক্ত করা উচিত।
এর অন্য বিশাল সুবিধাটি enum
হ'ল এটি পরবর্তী বিকাশকারীকে ঠিক সামনে সামনে বৈধ সরঞ্জামের ধরণের একটি সম্পূর্ণ তালিকা দেয়। বব'র বিশেষায়িত বাঁশি শ্রেণিটি যা তিনি তাঁর মহাকাব্যিক বসের যুদ্ধে ব্যবহার করেন তা খুঁজে পাওয়ার জন্য কোডটি ভেঙে যাওয়ার দরকার নেই।
void damageWargear(Tool* tool)
{
switch(tool->type)
{
case Tool::kSword:
static_cast<Sword*>(tool)->damageSword();
break;
case Tool::kShield:
static_cast<Sword*>(tool)->damageShield();
break;
default:
break; // Ignore all other objects
}
}
হ্যাঁ, আমি একটি "খালি" ডিফল্ট বিবৃতি রেখেছি, কেবল পরবর্তী বিকাশকারীকে এটি স্পষ্ট করে তুলতে যদি আমার কাছে কিছু নতুন অপ্রত্যাশিত প্রকার আসে তবে আমি কী ঘটতে আশা করি।
আপনি যদি এটি করেন তবে প্যাটার্নটি কম গন্ধ পাবে। যাইহোক, গন্ধমুক্ত থাকতে আপনাকে শেষ বিকল্পটি করতে হবে অন্য বিকল্পগুলি বিবেচনা করা। এই ক্যাসেটগুলি আপনার সি ++ রিপোর্টারে থাকা আরও কয়েকটি শক্তিশালী এবং বিপজ্জনক সরঞ্জাম। আপনার যদি ভাল কারণ না থাকে তবে এগুলি ব্যবহার করা উচিত নয়।
একটি খুব জনপ্রিয় বিকল্প হ'ল আমি যাকে "ইউনিয়ন কাঠামো" বা "ইউনিয়ন শ্রেণি" বলি। আপনার উদাহরণস্বরূপ, এটি আসলে খুব ভাল ফিট হবে। এর মধ্যে একটি তৈরি করার জন্য, আপনি Tool
আগের মতো একটি গণনা সহ একটি শ্রেণি তৈরি করেন , তবে সাবক্লাসিংয়ের পরিবর্তে Tool
, আমরা কেবলমাত্র প্রতিটি সাব-টাইপ থেকে সমস্ত ক্ষেত্র এটির উপরে রেখেছি।
class Tool {
public:
enum TypeE {
kSword,
kShield,
kMagicCloth
};
TypeE type;
int attack;
int defense;
};
এখন আপনার মোটেও সাবক্লাসের দরকার নেই। type
অন্যান্য ক্ষেত্রগুলি আসলে বৈধ কিনা তা দেখতে আপনাকে কেবল ক্ষেত্রটি দেখতে হবে। এটি অনেক বেশি নিরাপদ এবং বোঝা সহজ। তবে এর ঘাটতি রয়েছে। আপনি এটি ব্যবহার করতে চান না এমন সময় রয়েছে:
- যখন বস্তুগুলি খুব ভিন্ন হয় - আপনি ক্ষেত্রগুলির লন্ড্রি তালিকার সাথে শেষ করতে পারেন এবং এটি প্রতিটি স্পেসের ধরণের ক্ষেত্রে প্রযোজ্য তা অস্পষ্ট হতে পারে।
- কোনও স্মৃতি-সঙ্কটজনক পরিস্থিতিতে কাজ করার সময় - আপনার যদি 10 টি সরঞ্জাম তৈরি করতে হয় তবে আপনি স্মৃতিশক্তি নিয়ে অলস হতে পারেন। আপনার যখন 500 মিলিয়ন সরঞ্জাম তৈরি করতে হবে তখন আপনি বিট এবং বাইটগুলি দেখাশোনা করতে যাচ্ছেন। ইউনিয়ন স্ট্রাক্টগুলি তাদের প্রয়োজনের চেয়ে সর্বদা বড় are
ইউআইআইএক্স সকেটগুলির দ্বারা এই সমাধানটি ব্যবহার করা হয় না কারণ এপিআই-এর খোলামেলা সমাপ্তি দ্বারা মিশ্রিত ভিন্নতা ইস্যুটির কারণে। ইউএনআইএক্স সকেটগুলির উদ্দেশ্যটি এমন কিছু তৈরি করা ছিল যা ইউনিক্সের প্রতিটি স্বাদ কাজ করতে পারে। প্রতিটি স্বাদ তাদের সমর্থন করে এমন পরিবারগুলির তালিকা সংজ্ঞায়িত করতে পারে AF_INET
, এবং তাদের প্রত্যেকের জন্য একটি সংক্ষিপ্ত তালিকা থাকবে। তবে, যদি একটি নতুন প্রোটোকল আসে, যেমনটি AF_INET6
করে, আপনার নতুন ক্ষেত্র যুক্ত করতে পারে add আপনি যদি ইউনিয়ন কাঠামো দিয়ে এটি করেন, আপনি কার্যকরভাবে একই নামের সাথে স্ট্রাক্টের একটি নতুন সংস্করণ তৈরি করে অন্তহীন অসঙ্গতি সমস্যা তৈরি করে শেষ করবেন। এই কারণেই ইউনিক্স সকেটগুলি ইউনিয়ন কাঠামোর পরিবর্তে castালাই প্যাটার্নটি ব্যবহার করতে পছন্দ করেছিল। আমি নিশ্চিত যে তারা এটি বিবেচনা করেছে এবং তারা এটি সম্পর্কে ভেবে দেখেছিল যে তারা এটি ব্যবহার করার সময় কেন গন্ধ পায় না part
আপনি বাস্তবের জন্য একটি ইউনিয়নও ব্যবহার করতে পারেন। ইউনিয়নগুলি কেবল বৃহত্তম সদস্য হিসাবে বৃহত্তর হয়ে স্মৃতি সংরক্ষণ করে, তবে তারা তাদের নিজস্ব ইস্যু নিয়ে আসে। এটি সম্ভবত আপনার কোডের জন্য কোনও বিকল্প নয়, তবে এটি সর্বদা আপনার বিবেচনা করা উচিত।
আর একটি আকর্ষণীয় সমাধান হ'ল boost::variant
। বুস্ট একটি পুনরায় ব্যবহারযোগ্য ক্রস প্ল্যাটফর্ম সমাধানগুলিতে পূর্ণ একটি লাইব্রেরি। এটি সম্ভবত সেরা সি ++ কোডের কিছু লেখা। বুস্ট.ভেরিয়েন্ট মূলত ইউনিয়নগুলির সি ++ সংস্করণ। এটি এমন একটি ধারক যা বিভিন্ন ধরণের বিভিন্ন ধরণের ধারণ করতে পারে তবে একসাথে কেবলমাত্র একটি। আপনি আপনার Sword
, Shield
এবং MagicCloth
ক্লাসগুলি তৈরি করতে পারেন , তারপরে সরঞ্জামটিকে একটি হিসাবে পরিণত করতে পারেন boost::variant<Sword, Shield, MagicCloth>
, যার অর্থ এই তিন ধরণের একটি রয়েছে। এটি এখনও ভবিষ্যতের সামঞ্জস্যতার সাথে একই সমস্যার সাথে ভুগছে যা ইউনিক্স সকেটগুলি ব্যবহার করা থেকে বিরত করে (ইউএনআইএক্স সকেটগুলি সি হিসাবে উল্লেখ করা হয় না, ভবিষ্যদ্বাণী করেboost
কিছুটা হলেও!), তবে এই প্যাটার্নটি অবিশ্বাস্যভাবে কার্যকর হতে পারে। বৈকল্পিক প্রায়শই ব্যবহৃত হয়, উদাহরণস্বরূপ, পার্স গাছগুলিতে, যা পাঠ্যের একটি স্ট্রিং নেয় এবং নিয়মের জন্য ব্যাকরণ ব্যবহার করে এটি ভেঙে দেয়।
চূড়ান্ত সমাধান যা আমি নিমজ্জন নেওয়ার আগে জেনেরিক অবজেক্টের ingালাই পদ্ধতির ব্যবহার করার আগে দেখার পরামর্শ দিই তা হ'ল ভিজিটর ডিজাইন প্যাটার্ন। ভিজিটর একটি শক্তিশালী ডিজাইনের প্যাটার্ন যা পর্যবেক্ষণটির সুবিধা গ্রহণ করে যে ভার্চুয়াল ফাংশনটি কল করা কার্যকরভাবে আপনার প্রয়োজনীয় কাস্টিংটি করে এবং এটি এটি আপনার জন্য করে। কারণ সংকলক এটি করে, এটি কখনও ভুল হতে পারে না। সুতরাং, এনাম সংরক্ষণ করার পরিবর্তে, ভিজিটর একটি বিমূর্ত বেস ক্লাস ব্যবহার করে, যার একটি ভেটেবল রয়েছে যা জানে যে কী জিনিসটি টাইপ। তারপরে আমরা একটি ঝরঝরে সামান্য ডাবল-ইন্ডিরিশন কল তৈরি করি যা কাজ করে:
class Tool;
class Sword;
class Shield;
class MagicCloth;
class ToolVisitor {
public:
virtual void visit(Sword* sword) = 0;
virtual void visit(Shield* shield) = 0;
virtual void visit(MagicCloth* cloth) = 0;
};
class Tool {
public:
virtual void accept(ToolVisitor& visitor) = 0;
};
lass Sword : public Tool{
public:
virtual void accept(ToolVisitor& visitor) { visitor.visit(*this); }
int attack;
};
class Shield : public Tool{
public:
virtual void accept(ToolVisitor& visitor) { visitor.visit(*this); }
int defense;
};
class MagicCloth : public Tool{
public:
virtual void accept(ToolVisitor& visitor) { visitor.visit(*this); }
int attack;
int defense;
};
তাহলে এই godশ্বর আশ্চর্য প্যাটার্নটি কী? ওয়েল, Tool
একটি ভার্চুয়াল ফাংশন আছে accept
,। আপনি যদি এটি কোনও দর্শনার্থী পাস করেন তবে প্রত্যাশা করা visit
হয় যে এই ধরণের জন্য দর্শকের পক্ষে সঠিক ফাংশনটি কল করা হবে । visitor.visit(*this);
প্রতিটি উপ টাইপের ক্ষেত্রে এটিই হয় । জটিল, তবে আমরা উপরের উদাহরণ দিয়ে এটিকে প্রদর্শন করতে পারি:
class AttackVisitor : public ToolVisitor
{
public:
int& currentAttack;
int& currentDefense;
AttackVisitor(int& currentAttack_, int& currentDefense_)
: currentAttack(currentAttack_)
, currentDefense(currentDefense_)
{ }
virtual void visit(Sword* sword)
{
currentAttack += sword->attack;
}
virtual void visit(Shield* shield)
{
currentDefense += shield->defense;
}
virtual void visit(MagicCloth* cloth)
{
currentAttack += cloth->attack;
currentDefense += cloth->defense;
}
};
void Player::attack()
{
int currentAttack = this->attack;
int currentDefense = this->defense;
AttackVisitor v(currentAttack, currentDefense);
for (Tool* t: tools) {
t->accept(v);
}
//some other functions to start attack
}
তাহলে এখানে কী ঘটে? আমরা একটি ভিজিটর তৈরি করি যা আমাদের জন্য কিছু কাজ করবে, এটি একবার জানলে এটি কী ধরণের অবজেক্টে ভিজিট করছে। তারপরে আমরা সরঞ্জামগুলির তালিকাটি নিয়ে পুনরাবৃত্তি করি। যুক্তি দানের জন্য, আসুন প্রথম বস্তুটি একটি Shield
, তবে আমাদের কোডটি এখনও এটি জানে না। এটি কল করে t->accept(v)
, একটি ভার্চুয়াল ফাংশন। কারণ প্রথম অবজেক্টটি একটি ঝাল, এটি কলিংয়ের সমাপ্ত হয় void Shield::accept(ToolVisitor& visitor)
, যা কল করে visitor.visit(*this);
। এখন, আমরা যখন কোন visit
কলটি খুঁজছি , আমরা ইতিমধ্যে জানতে পারি যে আমাদের একটি ঝাল রয়েছে (কারণ এই ফাংশনটি ডেকেছে), তাই আমরা void ToolVisitor::visit(Shield* shield)
আমাদের সাথে যোগাযোগ করব AttackVisitor
। এটি এখন আমাদের প্রতিরক্ষা আপডেট করতে সঠিক কোড চালায় runs
দর্শনার্থী বিশাল। এটি এতটা ছোঁয়াচে যে আমি প্রায় এটির নিজস্ব গন্ধ আছে বলে মনে করি। খারাপ দর্শকদের নিদর্শনগুলি লেখা খুব সহজ। যাইহোক, এটির একটি বিশাল সুবিধা রয়েছে অন্যদের কোনওটিরই নয়। আমরা যদি কোনও নতুন সরঞ্জাম প্রকার যুক্ত করি তবে এর জন্য আমাদের একটি নতুন ToolVisitor::visit
ফাংশন যুক্ত করতে হবে। তাত্ক্ষণিকভাবে আমরা এটি করি, প্রোগ্রামের প্রতিটি ToolVisitor
সংকলন করতে অস্বীকার করবে কারণ এতে কোনও ভার্চুয়াল ফাংশন অনুপস্থিত। এটি এমন কিছু ক্ষেত্রে ধরা খুব সহজ করে তোলে যেখানে আমরা কিছু মিস করেছি। আপনি যদি কাজটি করতে বিবৃতি if
বা switch
বিবৃতি ব্যবহার করেন তবে গ্যারান্টি দেওয়া অনেক কঠিন । এই সুবিধাগুলি যথেষ্ট ভাল যে ভিজিটর 3 ডি গ্রাফিক্স দৃশ্যের জেনারেটরগুলির মধ্যে একটি দুর্দান্ত কুলুঙ্গি খুঁজে পেয়েছে। ভিজিটর যে ধরণের আচরণ দেয় তা তাদের ঠিক প্রয়োজন হয় তাই এটি দুর্দান্ত কাজ করে!
সব মিলিয়ে মনে রাখবেন যে এই নিদর্শনগুলি পরবর্তী বিকাশকারীকে শক্ত করে তোলে। তাদের জন্য এটিকে আরও সহজ করে দেওয়ার জন্য সময় ব্যয় করুন এবং কোডটি গন্ধ পাবে না!
* প্রযুক্তিগতভাবে, যদি আপনি অনুমানটি দেখুন, সোকাড্ডারের একটি সদস্যের নাম রয়েছে sa_family
। সি স্তরে এখানে কিছু কৌতুকপূর্ণ কাজ করা হচ্ছে যা আমাদের পক্ষে গুরুত্বপূর্ণ নয়। আপনি প্রকৃত বাস্তবায়নটি দেখার জন্য স্বাগত , তবে এই উত্তরের জন্য আমি sa_family
sin_family
এবং অন্যদের সম্পূর্ণরূপে বিনিময়যোগ্য হিসাবে ব্যবহার করতে যাচ্ছি , গদ্যের জন্য যে কোনও একটিই স্বজ্ঞাত, এটি বিশ্বাস করে যে সি ট্রিকরি গুরুত্বহীন বিবরণের যত্ন নেয়।