c++ - নিয়মিত কাস্ট বনাম static_cast বনাম dynamic_cast




pointers casting (6)

static_cast

static_cast কয়েকটি সীমাবদ্ধতা এবং সংযোজনগুলির সাথে আপনি মূলত একটি অন্তর্নিহিত রূপান্তর বিপরীত করতে চান এমন ক্ষেত্রে ক্ষেত্রে ব্যবহৃত হয়। static_cast কোন রানটাইম চেক সঞ্চালন করে। যদি আপনি জানেন যে আপনি একটি নির্দিষ্ট ধরনের বস্তুর উল্লেখ করেন তবে এটি ব্যবহার করা উচিত এবং এইভাবে একটি চেক অপ্রয়োজনীয় হবে। উদাহরণ:

void func(void *data) {
  // Conversion from MyClass* -> void* is implicit
  MyClass *c = static_cast<MyClass*>(data);
  ...
}

int main() {
  MyClass c;
  start_thread(&func, &c)  // func(&c) will be called
      .join();
}

এই উদাহরণে, আপনি জানেন যে আপনি একটি MyClass অবজেক্ট পাশ করেছেন এবং এইভাবে এটি নিশ্চিত করার জন্য রানটাইম চেকের কোন প্রয়োজন নেই।

dynamic_cast

যখন আপনি জানেন না যে ডায়নামিক গতির বস্তু কোনটি হয় তখন dynamic_cast কার্যকর। উল্লেখিত বস্তুটি বেস ক্লাস হিসাবে বর্ণিত প্রকারের ধারণ না করে এটি একটি bad_cast পয়েন্টার প্রদান করে (যখন আপনি একটি রেফারেন্সে নিক্ষেপ করেন, তখন সেই ক্ষেত্রে bad_cast ব্যতিক্রম নিক্ষেপ করা হয়)।

if (JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
  ...
} else if (ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
  ...
}

আপনি যদি dynamic_cast (একটি প্রাপ্ত শ্রেণিতে নিক্ষিপ্ত) ব্যবহার করেন এবং dynamic_cast না হয় তাহলে আপনি dynamic_cast ব্যবহার করতে পারবেন না। উদাহরণস্বরূপ, নিম্নলিখিত কোড বৈধ নয়, কারণ Base কোন ভার্চুয়াল ফাংশন নেই:

struct Base { };
struct Derived : Base { };
int main() {
  Derived d; Base *b = &d;
  dynamic_cast<Derived*>(b); // Invalid
}

একটি "আপ-কাস্ট" (বেস ক্লাসে ঢোকানো) static_cast এবং dynamic_cast উভয়ের সাথেই বৈধ এবং কোনও কাস্ট ছাড়াও "আপ-কাস্ট" একটি নিরপেক্ষ রূপান্তর।

নিয়মিত কাস্ট

এই casts এছাড়াও সি স্টাইল কাস্ট বলা হয়। সি-স্টাইল কাস্টটি মূলত সি ++ কাস্টগুলির ক্রমগুলির একটি পরিসর চেষ্টা করে এবং dynamic_cast বিবেচনা না করেই প্রথম সি ++ কাস্ট যা কাজ করে, তা গ্রহণ করতে একই রকম। বলার অপেক্ষা রাখে না, এটি আরো শক্তিশালী কারণ এটি const_cast , const_cast এবং reinterpret_cast এর সাথে একত্রিত করে তবে এটিও অনিরাপদ, কারণ এটি dynamic_cast ব্যবহার করে না।

উপরন্তু, সি-স্টাইল আপনাকে কেবল এটি করার অনুমতি দেয় না, তবে এটি আপনাকে একটি ব্যক্তিগত বেস-ক্লাসে নিরাপদে static_cast দেয়, যখন "সমান" static_cast ক্রমটি আপনাকে তার জন্য কম্পাইল-টাইম ত্রুটি দেবে।

কিছু মানুষ তাদের শৈশবের কারণে সি স্টাইল casts পছন্দ। আমি তাদের সংখ্যাসূচক কাস্টগুলির জন্য ব্যবহার করি, এবং ব্যবহারকারীরা সংজ্ঞায়িত ধরনের জড়িত থাকলে যথাযথ C ++ কাস্টগুলি ব্যবহার করে, কারণ তারা কঠোর পরীক্ষা প্রদান করে।

এই প্রশ্নটি ইতিমধ্যে একটি উত্তর আছে:

আমি প্রায় ২0 বছর ধরে সি এবং সি ++ কোড লিখেছি, কিন্তু এই ভাষাগুলির একটি দিক যা আমি কখনও বুঝতে পারিনি। আমি স্পষ্টভাবে নিয়মিত casts ব্যবহৃত হয়েছে

MyClass *m = (MyClass *)ptr;

সব জায়গাতেই, কিন্তু অন্য দুটি ধরণের কস্ট মনে হয়, এবং আমি পার্থক্যটি জানি না। কোড নিম্নলিখিত লাইনের মধ্যে পার্থক্য কি?

MyClass *m = (MyClass *)ptr;
MyClass *m = static_cast<MyClass *>(ptr);
MyClass *m = dynamic_cast<MyClass *>(ptr);

স্ট্যাটিক কাস্ট

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

char c = 10;       // 1 byte
int *p = (int*)&c; // 4 bytes

যেহেতু এই 4-বাইট পয়েন্টার বরাদ্দকৃত মেমরির 1 বাইটের দিকে নির্দেশ করে, এই পয়েন্টারটিকে লেখার ফলে রান-টাইম ত্রুটি হতে পারে অথবা কিছু সংলগ্ন মেমরি ওভাররাইট করবে।

*p = 5; // run-time error: stack corruption

সি স্টাইল কাস্টের বিপরীতে স্ট্যাটিক কাস্ট সংকলককে পয়েন্টার এবং পয়েন্টার ডেটা প্রকারগুলি উপযুক্ত বলে পরীক্ষা করার অনুমতি দেবে, যা প্রোগ্রামারকে সংকলনের সময় এই ভুল পয়েন্টার অ্যাসাইনমেন্টটি ধরতে দেয়।

int *q = static_cast<int*>(&c); // compile-time error

কাস্ট ব্যাখ্যা

পয়েন্টার রূপান্তরকে জোরদার করার জন্য, সি-স্টাইল কাস্টটি পটভূমিতে একইভাবে কাজ করে, তার পরিবর্তে কাস্টটি ব্যবহার করা হবে।

int *r = reinterpret_cast<int*>(&c); // forced conversion

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

গতিশীল কাস্ট

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

গতিশীল কাস্ট উদাহরণ

নীচের উদাহরণে, একটি MyChild পয়েন্টার একটি গতিশীল কাস্ট ব্যবহার করে একটি মাইবबेस পয়েন্টার রূপান্তর করা হয়। এই রূপান্তরিত-থেকে-বেস রূপান্তর সফল হয়েছে, কারণ শিশু বস্তুর একটি সম্পূর্ণ বেস অবজেক্ট রয়েছে।

class MyBase 
{ 
  public:
  virtual void test() {}
};
class MyChild : public MyBase {};



int main()
{
  MyChild *child = new MyChild();
  MyBase  *base = dynamic_cast<MyBase*>(child); // ok
}

পরবর্তী উদাহরণটি একটি মাইবबेस পয়েন্টারকে মাইচাইল্ড পয়েন্টারে রূপান্তর করার প্রচেষ্টা করে। যেহেতু বেস অবজেক্টটিতে একটি সম্পূর্ণ শিশু অবজেক্ট নেই তাই এই পয়েন্টার রূপান্তর ব্যর্থ হবে। এটি নির্দেশ করার জন্য, গতিশীল কাস্ট একটি নিল পয়েন্টার প্রদান করে। এটি রান-সময় চলাকালীন একটি রূপান্তর সফল হয়েছে কিনা তা পরীক্ষা করার জন্য একটি সুবিধাজনক উপায় দেয়।

MyBase  *base = new MyBase();
MyChild *child = dynamic_cast<MyChild*>(base);


if (child == 0) 
std::cout << "Null pointer returned";

একটি পয়েন্টার পরিবর্তে একটি রেফারেন্স পরিবর্তিত হয়, তাহলে গতিশীল কাস্ট একটি bad_cast ব্যতিক্রম নিক্ষেপ দ্বারা ব্যর্থ হবে। এটি একটি try-catch বিবৃতি ব্যবহার করে পরিচালনা করা প্রয়োজন।

#include <exception>
// …  
try
{ 
  MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e) 
{ 
  std::cout << e.what(); // bad dynamic_cast
}

গতিশীল বা স্ট্যাটিক কাস্ট

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

MyBase *base = static_cast<MyBase*>(child); // ok

তবে, দ্বিতীয় উদাহরণে রূপান্তরটি সফল বা ব্যর্থ হতে পারে। MyBase অবজেক্টটি একটি মাইবबेस ইনস্ট্যান্স থাকলে এটি ব্যর্থ হবে এবং যদি এটি একটি MyChild ইনস্ট্যান্স থাকে তবে এটি সফল হবে। কিছু পরিস্থিতিতে এটি রান-সময় পর্যন্ত পরিচিত হতে পারে না। এই ক্ষেত্রে গতিশীল কাস্ট স্ট্যাটিক কাস্ট চেয়ে একটি ভাল পছন্দ।

// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);

যদি একটি গতিশীল কাস্টের পরিবর্তে স্ট্যাটিক কাস্ট ব্যবহার করে বেস টু ডাইভিয়েড রূপান্তর করা হয় তবে রূপান্তর ব্যর্থ হতো না। এটি একটি অসম্পূর্ণ বস্তুর উল্লেখ একটি পয়েন্টার ফিরে আসতে হবে। যেমন একটি পয়েন্টার deferenferencing রান সময় ত্রুটি হতে পারে।

// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);

// Incomplete MyChild object dereferenced
(*child);

কাস্ট নিক্ষেপ

এই এক প্রাথমিকভাবে একটি পরিবর্তনশীল const সংযোজন যোগ বা অপসারণ করতে ব্যবহৃত হয়।

const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const

যদিও কনস্ট কাস্টটি ধ্রুবকের মান পরিবর্তন করতে দেয় তবে এটি করা এখনও অবৈধ কোড যা রান-টাইম ত্রুটি হতে পারে। ধ্রুবক শুধুমাত্র পঠনযোগ্য মেমরির একটি বিভাগে থাকলে এটি উদাহরণস্বরূপ ঘটতে পারে।

*nonConst = 10; // potential run-time error

কনস্টেস্টটি মূলত ব্যবহৃত হয় যখন একটি ফাংশন থাকে যা একটি অ-ধ্রুবক পয়েন্টার আর্গুমেন্ট নেয়, যদিও এটি পয়েন্টিকে সংশোধন করে না।

void print(int *p) 
{
   std::cout << *p;
}

ফাংশন তারপর একটি কনস্টেস্ট ব্যবহার করে একটি ধ্রুবক পরিবর্তনশীল পাস করা যেতে পারে।

print(&myConst); // error: cannot convert 
                 // const int* to int*

print(nonConst); // allowed

উত্স এবং আরো ব্যাখ্যা


আপনি নিবন্ধটি সি ++ প্রোগ্রামিং / টাইপ কাস্টিং এ দেখবেন।

এটি বিভিন্ন কাস্ট ধরনের সব ভাল বর্ণনা রয়েছে। নিচের লিংক থেকে নেওয়া নিম্নলিখিত:

const_cast

const_cast (expression) const_cast <> () একটি পরিবর্তনশীল এর const (ness) (বা ভলটিাইল-নেস) যুক্ত / অপসারণ করতে ব্যবহৃত হয়।

static_cast

static_cast (এক্সপ্রেশন) static_cast <> () পূর্ণসংখ্যা প্রকারের মধ্যে নিক্ষেপ করতে ব্যবহৃত হয়। 'যেমন' char-> দীর্ঘ, int-> সংক্ষিপ্ত ইত্যাদি

স্ট্যাটিক কাস্টও পয়েন্টারগুলিকে সংশ্লিষ্ট প্রকারগুলিতে নিক্ষেপ করার জন্য ব্যবহার করা হয়, উদাহরণস্বরূপ নিখরচায় প্রকারের কাস্টিং *।

dynamic_cast

ডায়নামিক কাস্টটি পয়েন্টার এবং রেফারেন্সগুলি রান-টাইম এ রূপান্তর করতে ব্যবহৃত হয়, সাধারণত একটি পয়েন্টার নিক্ষেপের উদ্দেশ্যে বা উত্তরাধিকার শৃঙ্খলা উত্তরাধিকার শৃঙ্খলা (উত্তরাধিকার শ্রেণীক্রম) উল্লেখ করে।

dynamic_cast (অভিব্যক্তি)

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

reinterpret_cast

ঢাল reinterpret সহজভাবে অন্য এক বিটwise বিরাম দেয়। কোন পয়েন্টার বা অবিচ্ছেদ্য টাইপ কাউন্টার reinterpret সঙ্গে অন্য কাউকে casted করা যাবে, সহজে অপব্যবহারের জন্য অনুমতি। উদাহরণস্বরূপ, কাস্ট একটিকে পুনরাবৃত্তি করে, অসহায়ভাবে, একটি স্ট্রিং পয়েন্টারে পূর্ণসংখ্যা পয়েন্টারটি নিক্ষেপ করুন।


সি স্টাইল কাস্ট ব্যবহার করে এড়িয়ে চলুন।

সি-স্টাইল কাস্টগুলি গঠন এবং কাস্টটিকে পুনরায় ব্যাখ্যা করার মিশ্রণ এবং আপনার কোডটি খুঁজে পাওয়া এবং প্রতিস্থাপন করা কঠিন। একটি সি ++ অ্যাপ্লিকেশন প্রোগ্রামার সি-শৈলী কাস্ট এড়াতে হবে।


dynamic_cast রানটাইম টাইপ পরীক্ষা করে এবং শুধুমাত্র রেফারেন্স এবং পয়েন্টারগুলির সাথে কাজ করে, static_cast রানটাইম টাইপ পরীক্ষণ অফার করে না। সম্পূর্ণ তথ্যের জন্য, MSDN নিবন্ধ static_cast অপারেটরটি দেখুন


dynamic_cast শুধুমাত্র পয়েন্টার এবং রেফারেন্স ধরনের সমর্থন করে। টাইপ একটি পয়েন্টার হয় বা টাইপ একটি রেফারেন্স টাইপ যদি একটি ব্যতিক্রম NULL যদি কাস্ট অসম্ভব যদি এটি NULL ফিরে। অতএব, dynamic_cast ব্যবহার করা যেতে পারে কিনা একটি বস্তু একটি নির্দিষ্ট ধরনের, static_cast করতে পারে না (আপনি কেবল একটি অবৈধ মান দিয়ে শেষ হবে)।

সি-স্টাইল (এবং অন্যান্য) কাস্টগুলি অন্য উত্তরের মধ্যে আচ্ছাদিত হয়েছে।







casting