সি ++ এ কোনও বস্তুর প্রকারের সন্ধান করা


147

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

আমার ফাংশনটিতে কোন ধরণের অবজেক্টটি পাস হয়েছে তা খুঁজে বের করার সর্বোত্তম উপায় কী?

উত্তর:


162

গতিশীল_কাস্টের কৌশলটি করা উচিত

TYPE& dynamic_cast<TYPE&> (object);
TYPE* dynamic_cast<TYPE*> (object);

dynamic_castশব্দ অন্য এক পয়েন্টার বা রেফারেন্স টাইপ থেকে একটি উপাত্ত কাস্ট, একটি রানটাইম পরীক্ষা করার ঢালাই বৈধতা নিশ্চিত করতে হবে।

যদি আপনি এমন কোনও ধরণের প্রকৃত অবজেক্টের মতো না হয়ে পয়েন্টারটি প্রেরণ করার চেষ্টা করেন, তবে কাস্টের ফলাফলটি NULL হবে। আপনি যদি এমন ধরণের প্রকৃত অবজেক্টের নয় এমন প্রসঙ্গে উল্লেখ করার চেষ্টা করেন, তবে কাস্ট bad_castব্যতিক্রম ছুঁড়ে ফেলবে ।

ডায়ামিক_কাস্ট কাজের জন্য বেস ক্লাসে কমপক্ষে একটি ভার্চুয়াল ফাংশন রয়েছে তা নিশ্চিত করুন।

উইকিপিডিয়া বিষয় রান টাইম টাইপ তথ্য

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


1
ডায়নামিক_কাস্ট কাজের জন্য বেস ক্লাসে একটি ভার্চুয়াল ফাংশন থাকতে হবে তার সাথে আপনি কী বোঝাতে চাইছেন। এটি আমার কাছে গুরুত্বপূর্ণ মনে হয়েছে, আমি কেবল অনুমান করব।
GiCo

3
ঠিক আছে এটি খুঁজে পেয়েছে: রান-টাইম টাইপ ইনফরমেশন (আরটিটিআই) কেবল বহুগঠিত ক্লাসগুলির জন্য উপলব্ধ, যার অর্থ তাদের কমপক্ষে একটি ভার্চুয়াল পদ্ধতি রয়েছে। গতিশীল_কাস্ট এবং টাইপিডের আরটিটিআই দরকার।
GiCo

dynamic_castএটি রূপান্তরযোগ্য না হলে নিক্ষেপ করবেন না ? কোনও ছোঁড়া তৈরি না করে এটি করার কোনও উপায় আছে কি?
jw

A* aptr = dynamic_cast<A*>(ptr);// এটি এর মতো হওয়ার কথা নয়
মেহেদী কারামোসালি

এটি কি PODs এর জন্য কাজ করে যা একটিতে ফেলে দেওয়া হয়েছে uint8_t*? অর্থাৎ আমি যে পরীক্ষা করতে পারবেন uint32_t* x = dynamic_cast<uint32_t*>(p), যেখানে pহয় uint8_t*? (আমি লঙ্ঘনের জন্য শাস্তি দেওয়ার চেষ্টা করছি)
jwww

157

আপনার সমস্যার বর্ণনার জন্য ডায়নামিক কাস্ট সেরা, তবে আমি কেবল এটি যুক্ত করতে চাই যে আপনি ক্লাসের ধরণটি এর সাথে খুঁজে পেতে পারেন:

#include <typeinfo>

...
string s = typeid(YourClass).name()

4
ভাল যদি আপনি সত্যিই না জানেন যে আপনার অবজেক্টটি কী। গৃহীত উত্তরটি আপনি ধরে নেন।
unludo

4
@ এক্সাস হ্যাঁ এটি স্টাড শিরোনামের অংশ
আমে জে

8
আমি কিভাবে দেখতে পাচ্ছি না । প্রকারের আইডি নামগুলি কার্যকর হওয়ার প্রয়োজন হয় না এবং এটি বাস্তবায়িত সংজ্ঞায়িত হয়।
জুতো

3
সর্বাধিক আকর্ষণীয় এখানে: একই শ্রেণীর উদাহরণগুলির নাম সমান হতে হবে না। তবে typeid নিজেই একই ক্লাসের দৃষ্টান্ত জন্য সমান তুলনা আছে, দেখতে stackoverflow.com/questions/1986418/typeid-versus-typeof-in-c
FourtyTwo

1
নোট জিসিসি ম্যাগলড নামটি দেয় যেমন 11MyClass। আনমাঙ্গল করতে আপনি এবিআই এক্সটেনশন লাইব্রেরিটি এতে ব্যবহার করতে পারেন cxxabi.h। এটি আপনাকে দেয় abi::__cxa_demangleযা আপনাকে আসল নাম দেবে
ডেভিড জি

27

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


4
সত্য। দুর্ভাগ্যক্রমে আমি একটি বিদ্যমান প্রকল্পে কাজ করছি যাতে আমি সত্যিই নকশা বা এ ক্লাস এ-তে কোনও কিছুই পরিবর্তন করতে পারি না
লেমননিস্কা

11

কেবলমাত্র সম্পূর্ণ হওয়ার জন্যই, আমি রোবোকাইড তৈরি করব এবং উল্লেখ করব যে typeidনামটি ব্যবহার না করেই একা ব্যবহার করা যেতে পারে:

#include <typeinfo>
#include <iostream>

using namespace std;

class A {
public:
    virtual ~A() = default; // We're not polymorphic unless we
                            // have a virtual function.
};
class B : public A { } ;
class C : public A { } ;

int
main(int argc, char* argv[])
{
    B b;
    A& a = b;

    cout << "a is B: " << boolalpha << (typeid(a) == typeid(B)) << endl;
    cout << "a is C: " << boolalpha << (typeid(a) == typeid(C)) << endl;
    cout << "b is B: " << boolalpha << (typeid(b) == typeid(B)) << endl;
    cout << "b is A: " << boolalpha << (typeid(b) == typeid(A)) << endl;
    cout << "b is C: " << boolalpha << (typeid(b) == typeid(C)) << endl;
}

আউটপুট:

a is B: true
a is C: false
b is B: true
b is A: false
b is C: false

9

সম্ভবত আপনার অবজেক্টগুলিতে একটি আইডি "ট্যাগ" এম্বেড করুন এবং এটি ক্লাস এ এর ​​বিষয়বস্তু এবং বি শ্রেণীর আইটের মধ্যে পার্থক্য করতে ব্যবহার করুন

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



4

কারণ আপনার ক্লাসটি বহুরূপী নয়। চেষ্টা করুন:

struct BaseClas { int base; virtual ~BaseClas(){} };
class Derived1 : public BaseClas { int derived1; };

এখন BaseClasবহুমুখী। আমি ক্লাসকে স্ট্রাক্টে পরিবর্তন করেছি কারণ একটি কাঠামোর সদস্যরা ডিফল্টরূপে সর্বজনীন।


3

আপনার বর্ণনাটি কিছুটা বিভ্রান্তিকর।

সাধারণভাবে বলতে গেলে, যদিও কিছু সি ++ বাস্তবায়নের ক্ষেত্রে এর জন্য পদ্ধতি রয়েছে, তবে আপনার প্রকারটি সম্পর্কে জিজ্ঞাসা করার কথা নেই। পরিবর্তে, আপনাকে A. এ নির্দেশকটিতে একটি গতিশীল_কাস্ট করার কথা রয়েছে এটি কী করবে তা রানটাইম এ, পয়েন্টের আসল বিষয়বস্তুগুলি চেক করা হবে। আপনার যদি বি থাকে, আপনি আপনার পয়েন্টারটি বি তে পাবেন অন্যথায়, আপনি একটি ব্যতিক্রম বা শূন্য পাবেন।


1
এটা আপনি একটি ব্যতিক্রম পাবেন উল্লেখ করা উচিত শুধুমাত্র যদি আপনি একটি রেফারেন্স ঢালাই যা ব্যর্থ সঞ্চালন। যেমন ডায়নামিক_কাস্ট <টি & টি (টি)। ব্যর্থ পয়েন্টার কাস্টগুলি NULL ফেরত দেয়। অর্থাত্ গতিশীল_কাস্ট <টি *> (টি)
আলফাজুলু

হ্যাঁ, আমার আরও ভাল করে স্পষ্ট করা উচিত ছিল। ধন্যবাদ। আমি আশা করি সি ধরণের বর্ণনায় এমন কোনও শব্দ রয়েছে যা বাই-রেফারেন্সের চেয়ে বাই-রেফারেন্স।
উরি

3

অন্যরা ইঙ্গিত হিসাবে আপনি গতিশীল_কাস্ট ব্যবহার করতে পারেন। তবে সাধারণত আপনি যে উদ্ভূত শ্রেণীর উপর কাজ করছেন তার ধরণের সন্ধানের জন্য ডায়নামিক_কাস্ট ব্যবহার করা খারাপ নকশাকে ইঙ্গিত করে। আপনি যদি প্যারামিটার হিসাবে A এর পয়েন্টার গ্রহণ করে এমন কোনও ক্রিয়াকলাপটি ওভাররাইড করছেন তবে এটি নিজে ক্লাস এ এর ​​পদ্ধতি / ডেটা দিয়ে কাজ করতে সক্ষম হওয়া উচিত এবং ক্লাস বি এর ডেটাগুলির উপর নির্ভর করা উচিত নয় যদি আপনার ক্ষেত্রে ওভাররাইড না করে আপনার ক্ষেত্রে নিশ্চিত যে আপনি যে পদ্ধতিটি লিখছেন তা কেবলমাত্র বি শ্রেণিতে কাজ করবে, তারপরে আপনার ক্লাস বিতে একটি নতুন পদ্ধতি রচনা করা উচিত are


1

অতিরিক্ত লোড ফাংশন ব্যবহার করুন। গতিশীল_কাস্ট বা এমনকি আরটিটিআই সমর্থন প্রয়োজন হয় না:

class A {};
class B : public A {};

class Foo {
public:
    void Bar(A& a) {
        // do something
    }
    void Bar(B& b) {
        Bar(static_cast<A&>(b));
        // do B specific stuff
    }
};

আসল প্রশ্ন থেকে সরাসরি: "আমি পরে কেবল বি এর সাথে ফাংশনগুলি কল করি" - এই জাতীয় ক্ষেত্রে কীভাবে ওভারলোডিং কাজ করবে?
মার্সিন গিল

আপনি যখন একটি এ দিয়ে বারকে কল করেন তখন কোনও বি স্টাফ হয় না। আপনি যখন বারকে একটি বি দিয়ে কল করেন তখন যে পদ্ধতিগুলি কেবল বি তে বিদ্যমান তা কল করা যেতে পারে। আপনি মূল প্রশ্নটি পড়েন? বারটি হ'ল "আমি এমন একটি ফাংশনকে ওভাররাইড করছি যা প্যারামিটার হিসাবে এ ধরণের একটি অবজেক্টকে গ্রহণ করে"
jmucchiello

7
এটি গতিশীল পলিমারফিজমে কাজ করে না, যা আমি সন্দেহ করি যে প্রশ্নকারী ব্যবহার করছে। সি ++ প্যারামিটারের রানটাইম ক্লাসের উপর ভিত্তি করে কোনও ওভারলোড নির্বাচন করতে পারে না, শুধুমাত্র সংকলন-টাইম টাইপের ভিত্তিতে।
স্টিভ জেসোপ

1

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

#include <iostream>
#include <boost/type_index.hpp>

int a;
int& ff() 
{
    return a;
}

int main() {
    ff() = 10;
    using boost::typeindex::type_id_with_cvr;
    std::cout << type_id_with_cvr<int&>().pretty_name() << std::endl;
    std::cout << type_id_with_cvr<decltype(ff())>().pretty_name() << std::endl;
    std::cout << typeid(ff()).name() << std::endl;
}

আশা করি এটি কার্যকর হবে।

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