Vtable এর অপরিজ্ঞাত রেফারেন্স


357

আমার সি ++ প্রোগ্রাম তৈরি করার সময় আমি ত্রুটির বার্তা পাচ্ছি

'vtable ... এর অপরিবর্তিত রেফারেন্স

এই সমস্যার কারণ কী? আমি কীভাবে এটি ঠিক করব?


এটি এমন হয় যে আমি নিম্নলিখিত কোডটির জন্য ত্রুটি পেয়ে যাচ্ছি (প্রশ্নে ক্লাসটি সিজেমোমডুল।) এবং সমস্যাটি কী তা আমি আমার জীবনের জন্য বুঝতে পারি না। প্রথমে, আমি ভেবেছিলাম এটি ভার্চুয়াল ফাংশনটিকে একটি দেহটি ভুলে যাওয়ার সাথে সম্পর্কিত, তবে যতদূর আমি বুঝতে পেরেছি, সবকিছু এখানে রয়েছে। উত্তরাধিকার শৃঙ্খলাটি কিছুটা দীর্ঘ, তবে এখানে সম্পর্কিত উত্স কোড। আমি নিশ্চিত না যে আমার অন্যান্য কী তথ্য সরবরাহ করতে হবে।

দ্রষ্টব্য: নির্মাতা যেখানে এই ত্রুটিটি ঘটছে, মনে হচ্ছে এটি।

আমার কোড:

class CGameModule : public CDasherModule {
 public:
  CGameModule(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
  : CDasherModule(pEventHandler, pSettingsStore, iID, 0, szName)
  { 
      g_pLogger->Log("Inside game module constructor");   
      m_pInterface = pInterface; 
  }

  virtual ~CGameModule() {};

  std::string GetTypedTarget();

  std::string GetUntypedTarget();

  bool DecorateView(CDasherView *pView) {
      //g_pLogger->Log("Decorating the view");
      return false;
  }

  void SetDasherModel(CDasherModel *pModel) { m_pModel = pModel; }


  virtual void HandleEvent(Dasher::CEvent *pEvent); 

 private:



  CDasherNode *pLastTypedNode;


  CDasherNode *pNextTargetNode;


  std::string m_sTargetString;


  size_t m_stCurrentStringPos;


  CDasherModel *m_pModel;


  CDasherInterfaceBase *m_pInterface;
};

থেকে উত্তরাধিকারী ...

class CDasherModule;
typedef std::vector<CDasherModule*>::size_type ModuleID_t;

/// \ingroup Core
/// @{
class CDasherModule : public Dasher::CDasherComponent {
 public:
  CDasherModule(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, ModuleID_t iID, int iType, const char *szName);

  virtual ModuleID_t GetID();
  virtual void SetID(ModuleID_t);
  virtual int GetType();
  virtual const char *GetName();

  virtual bool GetSettings(SModuleSettings **pSettings, int *iCount) {
    return false;
  };

 private:
  ModuleID_t m_iID;
  int m_iType;
  const char *m_szName;
};

যা উত্তরাধিকার সূত্রে ....

namespace Dasher {
  class CEvent;
  class CEventHandler;
  class CDasherComponent;
};

/// \ingroup Core
/// @{
class Dasher::CDasherComponent {
 public:
  CDasherComponent(Dasher::CEventHandler* pEventHandler, CSettingsStore* pSettingsStore);
  virtual ~CDasherComponent();

  void InsertEvent(Dasher::CEvent * pEvent);
  virtual void HandleEvent(Dasher::CEvent * pEvent) {};

  bool GetBoolParameter(int iParameter) const;
  void SetBoolParameter(int iParameter, bool bValue) const;

  long GetLongParameter(int iParameter) const;
  void SetLongParameter(int iParameter, long lValue) const;

  std::string GetStringParameter(int iParameter) const;
  void        SetStringParameter(int iParameter, const std::string & sValue) const;

  ParameterType   GetParameterType(int iParameter) const;
  std::string     GetParameterName(int iParameter) const;

 protected:
  Dasher::CEventHandler *m_pEventHandler;
  CSettingsStore *m_pSettingsStore;
};
/// @}


#endif

কোন কাজটি "ভিটিবেলের অনির্ধারিত রেফারেন্স ..." ফেলে দিচ্ছে?
জে। পোলফার

3
আমি সম্পূর্ণরূপে মিস করেছি যে ত্রুটি বার্তা একটি ফাংশন নির্দিষ্ট করে। এটি কনস্ট্রাক্টর হিসাবে ঘটে তাই আমি আমার ক্লাসের নামটি দেখেছি এবং সংযোগটি তৈরি করি নি। সুতরাং, কনস্ট্রাক্টর এটি নিক্ষেপ করছে। আমি আমার মূল পোস্টে সেই বিবরণ যুক্ত করব।
RyanG

3
আপনি যদি নতুন প্রকল্প তৈরির জন্য উল্লেখযোগ্য পরিবর্তনগুলি (যেমন qmake -projectএবং তারপরে qmake) করার পরেও আপনার প্রকল্প ফাইলগুলি পুনরায় তৈরি না করেন Makefile, তবে Qt ব্যবহার করার সময় এটি ত্রুটির সম্ভাব্য উত্স।
ডেভিড সি র্যাঙ্কিন

@ ডেভিডসি.র্যাঙ্কিন, অন্য কিউটি সম্পর্কিত সমস্যা হ'ল যদি ফাইলটি Q_OBJECTবাহ্যিকভাবে অনুলিপি করা হয় তবে এখনও .pro ফাইলের অংশ না হয় তবে এটি সূক্ষ্ম সংকলন করলেও এটি লিঙ্ক করে না। সক্ষম হবার জন্য আমাদের সেই .h/.cppফাইলটি .pro ফাইলে যুক্ত করতে হবে qmake
আইম্মিলিন্ড

উত্তর:


420

জিসিসি প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী এটিতে একটি এন্ট্রি আছে:

সমাধানটি নিশ্চিত করা হয় যে খাঁটি নয় এমন সমস্ত ভার্চুয়াল পদ্ধতি সংজ্ঞায়িত করা হয়েছে। নোট করুন যে কোনও ডেস্ট্রাক্টরকে অবশ্যই নির্ধারণ করা উচিত এমনকি যদি এটি খাঁটি-ভার্চুয়াল [class.dtor] / 7 হিসাবে ঘোষণা করা হয়।


17
nm -C CGameModule.o | grep CGameModule::আপনার সম্পূর্ণ শ্রেণি বাস্তবায়ন লজিকাল অবজেক্ট ফাইলে চলেছে ধরে ধরেই সংজ্ঞায়িত পদ্ধতিগুলির তালিকা দেবে। আপনি কী মিস করেছেন তা নির্ধারণের জন্য ভার্চুয়াল হিসাবে সংজ্ঞায়িত হিসাবে আপনি এটি তুলনা করতে পারেন।
ট্রয় ড্যানিয়েলস

132
এফএফএস, সংকলক কেন এটি পরীক্ষা করে না এবং ত্রুটি বার্তা প্রিন্ট করে না?
লেনার হোয়েট

20
স্পষ্টতই, এটি কেবল সংযোগকারী নয়, লিংক দ্বারা আবিষ্কার করা যেতে পারে।
Xoph

2
আমার ক্ষেত্রে আমাদের বিমূর্ত ক্লাস ছিল যা ধ্বংসকারী বাস্তবায়ন করেনি। আমাকে ফাঁকা বাস্তবায়ন ~ মাইক্লাস () {
put রাখতে হয়েছিল

1
আপনি লিঙ্কটি চেষ্টা করার চেষ্টা করছেন এমন বস্তুগুলি সংরক্ষণাগার (লিবক্সিজ.এ ফাইল) থেকে অনুপস্থিত থাকলে আপনি এই জাতীয় একটি ত্রুটি পেতে পারেন: obj অবজেক্টফিলামের জন্য vtable '
কেমিন

162

এটি মূল্যবান কিসের জন্য, ভার্চুয়াল ডেস্ট্রাক্টরের উপর একটি শরীর ভুলে যাওয়া নিম্নলিখিত উত্পন্ন করে:

C CYourClass এর জন্য vtable 'এর অপরিবর্তিত রেফারেন্স।

আমি একটি নোট যুক্ত করছি কারণ ত্রুটি বার্তাটি প্রতারণামূলক। (এটি ছিল জিসিসি সংস্করণ ৪.6.৩।)


23
আমাকে স্পষ্টভাবে আমার খালি ভার্চুয়াল ডেস্ট্রাক্টরের দেহটি সংজ্ঞা ফাইল (* .cc) এ দিতে হয়েছিল। এটি শিরোনামে থাকা আমার ত্রুটিটি দিয়েছে।
পপকর্নকিং

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

1
@ পোপকর্নকিং আমি একই সমস্যাটি দেখেছি। এমনকি ~Destructor = default;শিরোলেখ ফাইলটিতে সংজ্ঞায়িত করাও সহায়ক হয়নি। জিসিসির বিরুদ্ধে দস্তাবেজযুক্ত বাগ রয়েছে কি?
আরডি

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

এটি আমার সমস্যার সমাধান করে, ভার্চুয়াল ডেস্ট্রাক্টরের জন্য একটি খালি}} শরীর যুক্ত করে ত্রুটিটি এড়িয়ে চলে।
বোগদান আয়নিটজা

55

সুতরাং, আমি বিষয়টি সন্ধান করেছি এবং এটি খারাপ যুক্তির সংমিশ্রণ এবং অটোমেক / অটোটুলস বিশ্বের সাথে পুরোপুরি পরিচিত নয়। আমি আমার Makefile.am টেমপ্লেটে সঠিক ফাইলগুলি যুক্ত করেছিলাম, তবে আমাদের বিল্ড প্রক্রিয়ায় কোন পদক্ষেপটি আসলে মেকফিল তৈরি করেছে তা নিশ্চিত ছিলাম না। সুতরাং, আমি একটি পুরানো মেকফিলের সাথে সংকলন করছি যা আমার নতুন ফাইলগুলি সম্পর্কে কোনও ধারণা ছিল না।

প্রতিক্রিয়া এবং জিসিসি FAQ- এর লিঙ্কের জন্য ধন্যবাদ। সত্যিকারের কারণে এই সমস্যাটি এড়াতে আমি তা নিশ্চিত হতে পারি।


43
সংক্ষেপে: .cpp কেবল বিল্ডটিতে অন্তর্ভুক্ত ছিল না। ত্রুটি বার্তাটি সত্যই বিভ্রান্তিকর।
অফির্মো

66
কিউটি ব্যবহারকারীদের জন্য: আপনি যদি কোনও শিরোনামকে উপহাস করতে ভুলে যান তবে আপনি একই ত্রুটিটি পেতে পারেন।
ক্রিস মুলিয়ার

8
আমি মনে করি আপনার আলেকজান্দ্রে হামেজের উত্তরটি গ্রহণ করা উচিত। এই ত্রুটিটি অনুসন্ধান করা লোকদের সম্ভবত আপনার পরিবর্তে তার সমাধানের প্রয়োজন হবে।
টিম

13
-1 এটি আপনার সমস্যার সমাধান হতে পারে, তবে এটি মূল প্রশ্নের উত্তর নয়। সঠিক উত্তরটি হ'ল আপনি প্রয়োজনীয় প্রতীক সহ কোনও বস্তু ফাইল সরবরাহ করেন নি। আপনি কেন তাদের সরবরাহ করতে ব্যর্থ হলেন তা অন্য গল্প।
ওয়াল্টার

12
@ ওয়াল্টার: আসলে এটিই আমি সঠিক উত্তরটি খুঁজছিলাম। অন্যগুলি সুস্পষ্ট এবং এইভাবে সাহায্যহীন।
এডগার বোনেট

50

আপনি যদি Qt ব্যবহার করছেন তবে qmake পুনরায় চালু করার চেষ্টা করুন। যদি এই ত্রুটিটি উইজেটের ক্লাসে থাকে তবে কুইমেক লক্ষ্য করতে ব্যর্থ হতে পারে যে ইউআই ক্লাসের ভেটেবলটি নতুনভাবে তৈরি করা উচিত। এটি আমার জন্য সমস্যাটি স্থির করেছে।


2
আমি ঠিক তৈরি করে পুরো ফোল্ডারটি মুছে ফেলেছিলাম এটি কাজ করে।
টোমা জ্যাটো - মনিকা পুনরায় ইনস্টল করুন

এটি অনন্য নয় qmake, আমার সাথে একই ছিল cmake। সমস্যাটি হ'ল উভয় সরঞ্জামের শিরোনাম ফাইলগুলির সাথে কিছুটা সমস্যা রয়েছে যা প্রয়োজনের সময় সর্বদা পুনর্নির্মাণকে ট্রিগার করতে পারে না।
এমএসএলটাররা

2
ভেবেছিলেন "পুনর্নির্মাণ" পুনরায় কমনকে স্বয়ংক্রিয়ভাবে ... দৃশ্যত নয়। আপনার পরামর্শে আমি "রান কিমাকে" করেছি, তারপরে "পুনর্নির্মাণ" এবং এটি আমার সমস্যার সমাধান করেছে।
ইয়ানো

45

নিম্নলিখিত অবস্থার কারণে ভেটেবলের অনির্ধারিত রেফারেন্সও ঘটতে পারে। শুধু এটি চেষ্টা করুন:

ক্লাস এ অন্তর্ভুক্ত:

virtual void functionA(parameters)=0; 
virtual void functionB(parameters);

ক্লাস বি রয়েছে:

  1. উপরের ফাংশনএর সংজ্ঞা।
  2. উপরের ফাংশনবি জন্য সংজ্ঞা।

ক্লাস সি অন্তর্ভুক্ত: এখন আপনি একটি ক্লাস সি লিখছেন যেখানে আপনি এটি ক্লাস এ থেকে প্রাপ্ত করতে চলেছেন writing

এখন আপনি যদি সংকলনের চেষ্টা করেন তবে ক্লাস সি এর ত্রুটি হিসাবে ভেটেবলের অনির্ধারিত রেফারেন্স পাবেন।

কারণ:

functionAখাঁটি ভার্চুয়াল হিসাবে সংজ্ঞায়িত করা হয়েছে এবং এর সংজ্ঞাটি বি বিতে সরবরাহ করা হয়েছে ভার্চুয়াল হিসাবে সংজ্ঞায়িত (নির্ভেজাল ভার্চুয়াল functionBনয়) সুতরাং এটি ক্লাস এতেই এর সংজ্ঞা সন্ধানের চেষ্টা করে তবে আপনি ক্লাস বিতে তার সংজ্ঞাটি সরবরাহ করেছেন।

সমাধান:

  1. বি খাঁটি ভার্চুয়াল হিসাবে বি তৈরি করুন (আপনার যদি এর মতো প্রয়োজন থাকে) virtual void functionB(parameters) =0; (এটি কাজ করে এটি পরীক্ষা করা হয়)
  2. এটিকে ভার্চুয়াল হিসাবে রেখে ক্লাস এতে ফাংশনবিয়ের জন্য সংজ্ঞা সরবরাহ করুন। (আশা করি এটি কাজ করে যেমন আমি চেষ্টা করেছিলাম না)

@ ilya1725 আপনার প্রস্তাবিত সম্পাদনাটি কেবল ফর্ম্যাট এবং ঠিক মতো ফিক্সিং নয়, আপনি উত্তরও পরিবর্তন করছেন, উদাহরণস্বরূপ যে ক্লাস সি A এর পরিবর্তে বি থেকে উদ্ভূত হয়েছে এবং আপনি দ্বিতীয় সমাধানটি পরিবর্তন করছেন। এটি যথেষ্ট উত্তরটি পরিবর্তন করে। এই ক্ষেত্রে, দয়া করে পরিবর্তে লেখকের কাছে একটি মন্তব্য দিন। ধন্যবাদ!
ফ্যাবিও বলেছেন মনিকা

@ ফ্যাবিটুরাতি তখন থেকে ক্লাস সি উত্তরাধিকারসূত্রে উত্তীর্ণ কি? বাক্যটি পরিষ্কার নয়। এছাড়াও, "ক্লাস সি অন্তর্ভুক্ত:" এর অর্থ কী?
ilya1725

@ ilya1725 এই উত্তরটি খুব পরিষ্কার নয়, এবং আমি এটি সম্পাদনা এবং এটির উন্নতির বিরুদ্ধে নই। আমি যা বলছি তা হ'ল আপনার সম্পাদনা উত্তরের অর্থ পরিবর্তন করে এবং এটি খুব কঠোর পরিবর্তন। আশা করি, লেখক পদক্ষেপ নেবেন এবং তার অর্থ কী তা বোঝাবেন (যদিও তিনি দীর্ঘদিন ধরে নিষ্ক্রিয় ছিলেন)।
ফ্যাবিও মনিকাকে

ধন্যবাদ! আমার ক্ষেত্রে, আমার শ্রেণিবিন্যাসে আমার মাত্র 2 টি ক্লাস ছিল। ক্লাস এ খাঁটি ভার্চুয়াল পদ্ধতি ঘোষণা করেছে। ক্লাস বি এর ঘোষণায় বলা হয়েছে যে এটি এই পদ্ধতিটিকে ওভাররাইড করবে, তবে আমি এখনও ওভারডেন পদ্ধতির সংজ্ঞাটি লিখিনি।
নিক দেশালিউনার্স

44

আমি কেবল এই ত্রুটিটি পেয়েছি কারণ আমার সিপিপি ফাইলটি মেকফাইলে ছিল না।


আসলে, জড়িত কিছু undefined reference to {function/class/struct}আছে যখন বার্তাটি স্বাভাবিক থেকে কিছুটা পরিবর্তিত হয় virtualinvolved আমাকে ফেলে দিল
কিথ এম

30

কি vtable ?

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

একটি vtable মূলত এর সবচেয়ে সাধারণ বাস্তবায়ন পলিমরফিজম সি ++ এ । যখন ভেটেবল ব্যবহার করা হয়, প্রতিটি পলিমারফিক ক্লাসের প্রোগ্রামের কোথাও একটি ভিটিবেল থাকে; আপনি এটিকে staticক্লাসের একজন (লুকানো) ডেটা সদস্য হিসাবে ভাবতে পারেন । পলিমারফিক ক্লাসের প্রতিটি অবজেক্ট তার সর্বাধিক উদ্ভূত শ্রেণীর জন্য vtable এর সাথে যুক্ত। এই সমিতিটি পরীক্ষা করে, প্রোগ্রামটি তার বহুবিধ যাদুতে কাজ করতে পারে। গুরুত্বপূর্ণ সতর্কতা : একটি vtable একটি বাস্তবায়ন বিশদ। এটি সি ++ স্ট্যান্ডার্ড দ্বারা বাধ্যতামূলক করা হয় না, যদিও বেশিরভাগ (সমস্ত?) সি ++ সংকলকরা পলিমারফিক আচরণ বাস্তবায়নের জন্য ভিটিবেল ব্যবহার করেন। আমি যে বিবরণগুলি উপস্থাপন করছি তা হয় সাধারণ বা যুক্তিসঙ্গত পন্থা are সংকলকদের এ থেকে বিচ্যুত হওয়ার অনুমতি দেওয়া হয়!

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

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

কোথায় / কখন vtableউত্পন্ন হয়?

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

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

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

জিসিসি দ্বারা নির্বাচিত সদস্য (এবং অন্যান্য সংকলক দ্বারা সম্ভাব্য) প্রথম অ-ইনলাইন ভার্চুয়াল ফাংশন যা খাঁটি ভার্চুয়াল নয়। আপনি যদি সেই জনতার অংশ হয়ে থাকেন যা অন্যান্য সদস্যের কার্যের আগে নির্মাতা এবং ধ্বংসকারীদের ঘোষণা করে, তবে সেই ডেস্ট্রাক্টর নির্বাচিত হওয়ার ভাল সম্ভাবনা রয়েছে। (আপনি ধ্বংসকারীকে ভার্চুয়াল বানানোর কথা মনে করেন, তাই না?) ব্যতিক্রম আছে; আমি প্রত্যাশা করছিলাম যে ডাস্টস্ট্রাক্টরের জন্য যখন একটি ইনলাইন সংজ্ঞা প্রদান করা হয় এবং যখন ডিফল্ট ডেস্ট্রাক্টরকে অনুরোধ করা হয় (" = default" ব্যবহার করে ) তখন সর্বাধিক সাধারণ ব্যতিক্রমগুলি হয় ।

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

সংক্ষেপে, "ভিটেবলের অপরিজ্ঞাত রেফারেন্স" ত্রুটির তিনটি মূল কারণ রয়েছে:

  1. সদস্য ফাংশনটির সংজ্ঞাটি অনুপস্থিত।
  2. একটি অবজেক্ট ফাইল লিঙ্ক করা হচ্ছে না।
  3. সমস্ত ভার্চুয়াল ফাংশনগুলির ইনলাইন সংজ্ঞা রয়েছে।

এই কারণগুলি নিজেরাই ত্রুটি তৈরি করতে অপর্যাপ্ত। বরং ত্রুটি সমাধানের জন্য আপনি এগুলিই সম্বোধন করবেন। আশা করবেন না যে ইচ্ছাকৃতভাবে এই পরিস্থিতিগুলির একটি তৈরি করলে অবশ্যই এই ত্রুটি ঘটবে; অন্যান্য প্রয়োজনীয়তা আছে। আশা করবেন না যে এই পরিস্থিতিগুলি সমাধান করা এই ত্রুটিটি সমাধান করবে।

(ঠিক আছে, এই প্রশ্নটি জিজ্ঞাসা করা হলে 3 নম্বর যথেষ্ট ছিল)

ত্রুটি কিভাবে ঠিক করবেন?

এগিয়ে এড়ানো মানুষ ফিরে স্বাগতম! :)

  1. আপনার শ্রেণির সংজ্ঞা দেখুন। প্রথম নন-ইনলাইন ভার্চুয়াল ফাংশন সন্ধান করুন যা খাঁটি ভার্চুয়াল নয় (" = 0" নয়) এবং যার সংজ্ঞা আপনি সরবরাহ করেন (" = default" নয়)।
    • যদি এরকম কোনও কার্যকারিতা না থাকে তবে আপনার শ্রেণিটি সংশোধন করার চেষ্টা করুন যাতে একটি রয়েছে। (ত্রুটি সম্ভবত সমাধান হয়েছে))
    • একটি সতর্কতার জন্য ফিলিপ থমাসের উত্তরও দেখুন ।
  2. এই ফাংশনটির জন্য সংজ্ঞাটি সন্ধান করুন। যদি এটি অনুপস্থিত থাকে তবে এটি যুক্ত করুন! (ত্রুটি সম্ভবত সমাধান হয়েছে))
  3. আপনার লিঙ্ক কমান্ড পরীক্ষা করুন। যদি এটি ফাংশনের সংজ্ঞা সহ অবজেক্ট ফাইলটির উল্লেখ না করে তবে এটি ঠিক করুন! (ত্রুটি সম্ভবত সমাধান হয়েছে))
  4. ত্রুটি সমাধান না হওয়া অবধি প্রতিটি ভার্চুয়াল ফাংশনের জন্য 2 এবং 3 পদক্ষেপ পুনরাবৃত্তি করুন, তারপরে প্রতিটি অ-ভার্চুয়াল ফাংশনের জন্য। আপনি যদি এখনও আটকে থাকেন তবে প্রতিটি স্থির ডেটা সদস্যের জন্য পুনরাবৃত্তি করুন।

উদাহরণ
কী করা উচিত তার বিবরণগুলি পৃথক হতে পারে এবং কখনও কখনও পৃথক প্রশ্নে বিভক্ত হয় ( যেমন একটি অপরিজ্ঞাত রেফারেন্স / অমীমাংসিত বাহ্যিক প্রতীক ত্রুটি কী এবং আমি কীভাবে এটি ঠিক করব? )। যদিও আমি একটি নির্দিষ্ট ক্ষেত্রে কী করব তার একটি উদাহরণ প্রদান করব যা নতুন প্রোগ্রামারগুলিকে বিভ্রান্ত করতে পারে।

পদক্ষেপ 1 আপনার শ্রেণিটি সংশোধন করার উল্লেখ করেছে যাতে এটিতে একটি নির্দিষ্ট ধরণের ফাংশন থাকে। যদি সেই ফাংশনটির বিবরণটি আপনার মাথার উপরে চলে যায় তবে আপনি যে পরিস্থিতিতে আমি সম্বোধন করতে চান তা আপনি হতে পারেন। মনে রাখবেন যে লক্ষ্যটি অর্জনের এটি একটি উপায়; এটি একমাত্র উপায় নয় এবং সহজেই আপনার নির্দিষ্ট পরিস্থিতিতে আরও ভাল উপায় থাকতে পারে। আসুন আপনার ক্লাস কল A। আপনার ডেস্ট্রাক্টর কি হিসাবে ঘোষিত হয়েছে (আপনার শ্রেণির সংজ্ঞায়)

virtual ~A() = default;

অথবা

virtual ~A() {}

? যদি তা হয় তবে দুটি পদক্ষেপ আপনার ডিস্ট্রাক্টরকে আমাদের ফাংশনটির ধরণে পরিবর্তন করবে। প্রথমে সেই লাইনটি পরিবর্তন করুন

virtual ~A();

দ্বিতীয়ত, নিম্নলিখিত উত্সটি এমন একটি উত্স ফাইলে রাখুন যা আপনার প্রকল্পের অংশ (সাধারণত শ্রেণীর প্রয়োগের ফাইলটি যদি আপনার থাকে তবে):

A::~A() {}

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


ওহ, ব্র্যাভো! খুব বিস্তারিত এবং খুব ভাল স্কোপযুক্ত ব্যাখ্যা জন্য।
ডেভিড সি র্যাঙ্কিন

এটি পড়ার জন্য খুব দূরে যেতে স্ক্রোল করতে হয়েছিল। চমৎকার ব্যাখ্যা জন্য একটি upvote আছে!
টমাস

24

এখানে বিভিন্ন উত্তরে প্রচুর জল্পনা চলছে। আমি নীচে একটি মোটামুটি ন্যূনতম কোড দেব যা এই ত্রুটিটি পুনরুত্পাদন করে এবং এটি কেন ঘটছে তা ব্যাখ্যা করবে।

এই ত্রুটিটি পুনরুত্পাদন করার জন্য মোটামুটি ন্যূনতম কোড

IBase.hpp

#pragma once

class IBase {
    public:
        virtual void action() = 0;
};

Derived.hpp

#pragma once

#include "IBase.hpp"

class Derived : public IBase {
    public:
        Derived(int a);
        void action() override;
};

Derived.cpp

#include "Derived.hpp"
Derived::Derived(int a) { }
void Derived::action() {}

myclass.cpp

#include <memory>
#include "Derived.hpp"

class MyClass {

    public:
        MyClass(std::shared_ptr<Derived> newInstance) : instance(newInstance) {

        }

        void doSomething() {
            instance->action();
        }

    private:
        std::shared_ptr<Derived> instance;
};

int main(int argc, char** argv) {
    Derived myInstance(5);
    MyClass c(std::make_shared<Derived>(myInstance));
    c.doSomething();
    return 0;
}

আপনি এটির মতো জিসিসি ব্যবহার করে এটি সংকলন করতে পারেন:

g++ -std=c++11 -o a.out myclass.cpp Derived.cpp

আপনি এখন = 0IBase.hpp এ সরিয়ে ত্রুটিটি পুনরুত্পাদন করতে পারেন । আমি এই ত্রুটি পেয়েছি:

~/.../catkin_ws$ g++ -std=c++11 -o /tmp/m.out /tmp/myclass.cpp /tmp/Derived.cpp
/tmp/cclLscB9.o: In function `IBase::IBase(IBase const&)':
myclass.cpp:(.text._ZN5IBaseC2ERKS_[_ZN5IBaseC5ERKS_]+0x13): undefined reference to `vtable for IBase'
/tmp/cc8Smvhm.o: In function `IBase::IBase()':
Derived.cpp:(.text._ZN5IBaseC2Ev[_ZN5IBaseC5Ev]+0xf): undefined reference to `vtable for IBase'
/tmp/cc8Smvhm.o:(.rodata._ZTI7Derived[_ZTI7Derived]+0x10): undefined reference to `typeinfo for IBase'
collect2: error: ld returned 1 exit status

ব্যাখ্যা

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

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

পার্টিং টিপ

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

আরওএস এবং ক্যাটকিন বিল্ড সিস্টেমে নোট

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

add_executable(myclass src/myclass.cpp src/Derived.cpp)
add_dependencies(myclass theseus_myclass_cpp)
target_link_libraries(myclass ${catkin_LIBRARIES})

প্রথম লাইনটি মূলত বলেছে যে আমরা মাইক্লাস নামের একটি এক্সিকিউটেবল তৈরি করতে চাই এবং এটি তৈরির কোডটি নিম্নলিখিত ফাইলগুলি খুঁজে পেতে পারে। এই ফাইলগুলির মধ্যে একটিতে প্রধান () হওয়া উচিত। লক্ষ্য করুন যে আপনাকে CMakeLists.txt এ কোথাও .hpp ফাইলগুলি নির্দিষ্ট করতে হবে না। এছাড়াও আপনাকে ডেরিভড সিপিপি লাইব্রেরি হিসাবে নির্দিষ্ট করতে হবে না।


18

আমি এই ত্রুটির জন্য কেবল অন্য কোনও কারণের জন্য দৌড়েছি যা আপনি যাচাই করতে পারেন।

বেস ক্লাসটি একটি খাঁটি ভার্চুয়াল ফাংশনটিকে সংজ্ঞায়িত করেছে :

virtual int foo(int x = 0);

এবং সাবক্লাস ছিল

int foo(int x) override;

সমস্যাটি টাইপ ছিল যা অনুমিতির "=0"বাইরে থাকার কথা ছিল:

virtual int foo(int x) = 0;

সুতরাং, আপনি যদি এটিকে খুব নিচে স্ক্রোল করে থাকেন তবে সম্ভবত আপনি উত্তরটি খুঁজে পান নি - এটি যাচাই করার জন্য অন্য কিছু।


12

আপনি যদি সংজ্ঞাটি সহ অবজেক্ট ফাইলে লিঙ্ক করতে ভুলে যান তবে এটি খুব সহজেই ঘটতে পারে।


1
আপনার উত্তর এবং সম্ভাব্য সমাধানে আরও কিছু বিবরণ যুক্ত করুন add
মোহিত জৈন

1
লিঙ্ক করতে ভুলে যাওয়া নির্দেশাবলী তৈরি করতে ভুলে যাওয়া অন্তর্ভুক্ত করতে পারে। আমার ক্ষেত্রে, আমার সিপিসি ফাইলের উত্স তালিকায় সিপিপি ফাইল যুক্ত করতে ভুলে যাওয়া ব্যতীত আমার সিপিপি ফাইলের সমস্ত কিছু পুরোপুরি 'সংজ্ঞায়িত' ছিল (আমার সিএমকেলিস্ট.টেক্সট-এ, তবে অন্য বিল্ড সিস্টেমে যেমন একটি .pro ফাইলের ক্ষেত্রেও ঘটতে পারে) happen ফলস্বরূপ, সবকিছু কম্পাইল এবং তারপর আমি লিংক সময়ে ত্রুটি ... পেয়েছিলাম
ঋষি

@ মোহিত জৈন কীভাবে অবজেক্ট ফাইলগুলিতে লিঙ্ক করবেন তা পরিবেশ সেটআপ এবং সরঞ্জামদানের উপর নির্ভর করে। দুর্ভাগ্যক্রমে এক ব্যক্তির জন্য একটি নির্দিষ্ট ফিক্স অন্যের জন্য আলাদা হতে পারে (যেমন সিএমকে বনাম মালিকানা সরঞ্জাম বনাম আইডিই বনাম ইত্যাদি)
হজোক

11

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

সংকলকটি নির্বাচিত করতে পছন্দ করে vtable যেখানে একই স্থানে প্রথম ঘোষিত ভার্চুয়াল ফাংশনটি সংজ্ঞায়িত করা হয়েছে ঠিক তেমন জায়গায়

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

পার্শ্ব প্রতিক্রিয়া হিসাবে, দয়া করে নোট করুন যে কেবলমাত্র এই নির্দিষ্ট ভার্চুয়াল ফাংশনটির জন্য আপনি functionতিহ্যবাহী লিঙ্কারের ত্রুটি পাবেন না যেমন আপনি ফাংশন ফু নিচ্ছেন


8

পারাপারের জন্য নয়। যদি আপনি উত্তরাধিকার নিয়ে কাজ করেন তবে দ্বিতীয় গুগল হিটটি আমি যা হারিয়েছিলাম, অর্থাৎ। সমস্ত ভার্চুয়াল পদ্ধতি সংজ্ঞায়িত করা উচিত।

যেমন:

virtual void fooBar() = 0;

বিশদের জন্য উত্তরওয়্যার সি ++ অনির্ধারিত রেফারেন্স দেখুন। এটি ইতিমধ্যে উপরে উল্লিখিত রয়েছে তা বুঝতে পেরেছি, তবে হেক এটি কারওর পক্ষে সহায়তা করতে পারে।


8

ঠিক আছে, এর সমাধান হ'ল আপনি সংজ্ঞাটি বাদ দিয়েছেন। ভেটেবল সংকলক ত্রুটি এড়াতে নীচের উদাহরণটি দেখুন:

// In the CGameModule.h

class CGameModule
{
public:
    CGameModule();
    ~CGameModule();

    virtual void init();
};

// In the CGameModule.cpp

#include "CGameModule.h"

CGameModule::CGameModule()
{

}

CGameModule::~CGameModule()
{

}

void CGameModule::init()    // Add the definition
{

}

7
  • আপনি কি নিশ্চিত যে CDasherComponentধ্বংসকারীটির জন্য এটির একটি দেহ রয়েছে? এটি অবশ্যই এখানে নেই - প্রশ্নটি এটি যদি সিসি ফাইলে থাকে।
  • শৈলীর দৃষ্টিকোণ থেকে CDasherModuleস্পষ্টভাবে এর ধ্বংসকারীকে সংজ্ঞায়িত করা উচিত virtual
  • দেখে মনে হচ্ছে শেষে ( CGameModuleঅতিরিক্ত ) }পরে অতিরিক্ত রয়েছে }; // for the class
  • হয় CGameModuleলাইব্রেরি যে সংজ্ঞায়িত বিরুদ্ধে লিঙ্ক হচ্ছে CDasherModuleএবং CDasherComponent?

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

@ আরয়ানজি: সমস্ত ভার্চুয়াল ফাংশন সংজ্ঞা শ্রেণীর সংজ্ঞাতে স্থানান্তরিত করার চেষ্টা করুন। নিশ্চিত হয়ে নিন যে তারা সেখানে রয়েছে এবং ফলাফলটি পরিবর্তন হয়েছে কিনা তা দেখুন।
স্টিফেন

5

সম্ভবত ভার্চুয়াল ডেস্ট্রাক্টর অনুপস্থিত ফ্যাক্টর?

virtual ~CDasherModule(){};

5

এটি আমার জন্য প্রথম অনুসন্ধানের ফলাফল ছিল তাই আমি ভেবেছিলাম যে আমি আরও একটি জিনিস যাচাই করতে যুক্ত করব: নিশ্চিত করুন যে ভার্চুয়াল ফাংশনগুলির সংজ্ঞাটি আসলে ক্লাসে রয়েছে। আমার ক্ষেত্রে, আমার এটি ছিল:

শিরোনাম ফাইল:

class A {
 public:
  virtual void foo() = 0;
};

class B : public A {
 public:
  void foo() override;
};

এবং আমার .cc ফাইলটিতে:

void foo() {
  ...
}

এটি পড়া উচিত

void B::foo() {
}

3

সম্ভবত না। অবশ্যই ~CDasherModule() {}অনুপস্থিত।


3

এখানে অনেক উত্তর আছে তবে তাদের মধ্যে কেউই আমার সমস্যাটি কী তা অন্তর্ভুক্ত বলে মনে হয় নি। আমার নিম্নলিখিত ছিল:


class I {
    virtual void Foo()=0;
};

এবং অন্য একটি ফাইলে (অবশ্যই সংকলন এবং লিঙ্কিংয়ের অন্তর্ভুক্ত)

class C : public I{
    void Foo() {
        //bar
    }
};

ভাল এটি কাজ করে না এবং আমি যে ত্রুটিটির কথা বলছি তা পেয়েছি। এটির সমাধানের জন্য, আমাকে ফুয়ের আসল সংজ্ঞাটি শ্রেণীর ঘোষণার বাইরে নিয়ে যেতে হয়েছিল:

class C : public I{
    void Foo();
};

C::Foo(){
   //bar
}

আমি সি ++ গুরু নই তাই কেন এটি আরও সঠিক তা আমি ব্যাখ্যা করতে পারি না তবে এটি আমার জন্য সমস্যার সমাধান করেছে।


আমি কোনও সি ++ গুরু নই, তবে এটি একই সংজ্ঞা এবং সংজ্ঞাটিকে অতিরিক্ত সংজ্ঞা ফাইলের সাথে মিশ্রিত করার সাথে সম্পর্কিত বলে মনে হচ্ছে।
টেরি জি লরবার

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

3

তাই আমি উইন্ডোজ এক্সপি এবং মিনজিডাব্লু সংকলক সহ কিউটি ব্যবহার করছিলাম এবং এই জিনিসটি আমাকে পাগল করছে।

মূলত moc_xxx.cpp খালি জেনারেট হয়েছিল এমনকি আমি যুক্ত হওয়ার পরেও

Q_OBJECT

ফাংশন ভার্চুয়াল, সুস্পষ্ট এবং আপনার অনুমান যা কাজ করে না সবকিছু তৈরি করে মুছে ফেলা হচ্ছে। অবশেষে আমি লাইন দ্বারা লাইন অপসারণ শুরু করেছি এবং এটি আমার কাছে আছে তা দেখা গেল

#ifdef something

ফাইল চারপাশে। এমনকি যখন # আইডিডিফ সত্যিকারের এমওসি ফাইল তৈরি হয় নি।

সুতরাং সমস্ত #ifdefs অপসারণ সমস্যার সমাধান করে।

উইন্ডোজ এবং ভিএস 2013 এর সাথে এই জিনিসটি ঘটছিল না।


Q_OBJECT লাইনটি মন্তব্য করা আমার সাধারণ পরীক্ষার অ্যাপটিকে একটি সমতল দিয়ে তৈরি করেছে g++ *.cpp ...। (দ্রুত এবং নোংরা কিছু দরকার ছিল তবে চুম্বনে পূর্ণ ছিল কুমাক।)
নাথন কিদ

2

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


2

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

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


2

আমার ক্ষেত্রে আমি কিউটি ব্যবহার করছি এবং QObjectএকটিতে একটি সাবক্লাস সংজ্ঞায়িত করেছিfoo.cpp (নয় .h) ফাইলে । ফিক্স যোগ করার জন্য ছিল #include "foo.moc"শেষে foo.cpp


2

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

Foo.hpp:

class Foo
{
public:
    virtual void StartFooing();
};

Foo.cpp:

#include "Foo.hpp"

void Foo::StartFooing(){ //fooing }

সংকলিত:

g++ Foo.cpp -c

এবং main.cpp:

#include "Foo.hpp"

int main()
{
    Foo foo;
}

সংকলিত এবং এর সাথে সংযুক্ত:

g++ main.cpp -o main

আমাদের প্রিয় ত্রুটি দেয়:

/tmp/cclKnW0g.o: main': main.cpp:(.text+0x1a): undefined reference toFoo 'সংগ্রহ 2 এর জন্য ফাংশন ভিটিবেলে: ত্রুটি: ld 1 প্রস্থান স্থিতি ফিরে এসেছে

আমার অবিস্মরণীয় ঘটনা থেকে এই ঘটনা:

  1. সংকলন সময়ে ক্লাস প্রতি ভেটেবল তৈরি করা হয়

  2. Foo.o এ থাকা লিঙ্কারের ভিটিবেলে অ্যাক্সেস নেই


1

নিম্নলিখিত পরিস্থিতিতে আমি এই ত্রুটিটি পেয়েছি

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

এটি ঠিক করার জন্য, বিল্ডিংয়ের আগে, নিশ্চিত করুন যে আপনি শিরোনাম ফাইলটি (যা আপনি পরিবর্তন করেছেন) সাধারণ / অন্তর্ভুক্ত ডিরেক্টরিতে মুছে ফেলেছেন। এছাড়াও সুনির্দিষ্ট করুন যে আপনি সদ্য তৈরি নতুন .cpp ফাইল থেকে নির্মিত নতুন .o ফাইলকে যুক্ত / যুক্ত করতে আপনার মেকফিলটি পরিবর্তন করেছেন। আপনি যখন এই পদক্ষেপগুলি করেন তখন সংকলক / লিঙ্কার আর অভিযোগ করবে না।


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

1

আমি এমন পরিস্থিতিতে ত্রুটি পেয়েছি যেখানে আমি যখন কোনও মেইক বাগ পেয়েছিলাম যখন কোনও বস্তুর সাথে লিঙ্ক করার চেষ্টা করছিলাম তখন এটি সংরক্ষণাগারে যুক্ত করা যায় না।

বলুন আমার কাছে libXYZ.a আছে যা অনুমান করে বায়োসেক.ও রাখবে তবে তা তা নয়।

আমি একটি ত্রুটি পেয়েছি:

combineseq.cpp:(.text+0xabc): undefined reference to `vtable for bioseq'

এটি উপরের সমস্ত থেকে পৃথক করা হয়। সংরক্ষণাগার সমস্যাটিতে আমি এই নিখোঁজ বস্তুটিকে কল করব।


0

আপনার মতো কোনও বার্তা পাওয়াও সম্ভব

SomeClassToTest.host.o: In function `class1::class1(std::string const&)':
class1.hpp:114: undefined reference to `vtable for class1'
SomeClassToTest.host.o: In function `class1::~class1()':
class1.hpp:119: undefined reference to `vtable for class1'
collect2: error: ld returned 1 exit status
[link] FAILED: 'g++' '-o' 'stage/tests/SomeClassToTest' 'object/tests/SomeClassToTest.host.o' 'object/tests/FakeClass1.SomeClassToTest.host.o'

আপনি যখন অন্য শ্রেণীর সামারক্লাসের জন্য ইউনিট পরীক্ষার সাথে লিঙ্ক করার চেষ্টা করছেন তখন কোনও ক্লাস ফেকক্লাস 1 এর ভার্চুয়াল ফাংশনটি সংজ্ঞায়িত করতে ভুলে যান।

//class declaration in class1.h
class class1
{
    public:
    class1()
    {
    }
    virtual ~class1()
    {
    }
    virtual void ForgottenFunc();
};

এবং

//class definition in FakeClass1.h
//...
//void ForgottenFunc() {} is missing here

এই ক্ষেত্রে আমি আপনাকে আবার আপনার ক্লাস 1 এর জাল পরীক্ষা করার পরামর্শ দিচ্ছি। আপনি সম্ভবত দেখতে পাবেন যে আপনি নিজের ForgottenFuncনকল শ্রেণিতে ভার্চুয়াল ফাংশনটি সংজ্ঞায়িত করতে ভুলে গেছেন ।


0

আমি একটি বিদ্যমান উত্স / শিরোনামের জুটিতে দ্বিতীয় শ্রেণি যুক্ত করার সময় আমি এই ত্রুটিটি পেয়েছি। একই .h ফাইলে দুটি শ্রেণির শিরোনাম, এবং একই .cpp ফাইলে দুটি শ্রেণির ফাংশন সংজ্ঞা।

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


ব্যর্থ প্রচেষ্টা:

_gui_icondata.h:

#ifndef ICONDATA_H
#define ICONDATA_H

class Data;
class QPixmap;

class IconData
{
public:
    explicit IconData();
    virtual ~IconData();

    virtual void setData(Data* newData);
    Data* getData() const;
    virtual const QPixmap* getPixmap() const = 0;

    void toggleSelected();
    void toggleMirror();
    virtual void updateSelection() = 0;
    virtual void updatePixmap(const QPixmap* pixmap) = 0;

protected:
    Data* myData;
};

//--------------------------------------------------------------------------------------------------

#include "_gui_icon.h"

class IconWithData : public Icon, public IconData
{
    Q_OBJECT
public:
    explicit IconWithData(QWidget* parent);
    virtual ~IconWithData();

    virtual const QPixmap* getPixmap() const;
    virtual void updateSelection();
    virtual void updatePixmap(const QPixmap* pixmap);

signals:

public slots:
};

#endif // ICONDATA_H

_gui_icondata.cpp:

#include "_gui_icondata.h"

#include "data.h"

IconData::IconData()
{
    myData = 0;
}

IconData::~IconData()
{
    if(myData)
    {
        myData->removeIcon(this);
    }
    //don't need to clean up any more; this entire object is going away anyway
}

void IconData::setData(Data* newData)
{
    if(myData)
    {
        myData->removeIcon(this);
    }
    myData = newData;
    if(myData)
    {
        myData->addIcon(this, false);
    }
    updateSelection();
}

Data* IconData::getData() const
{
    return myData;
}

void IconData::toggleSelected()
{
    if(!myData)
    {
        return;
    }

    myData->setSelected(!myData->getSelected());
    updateSelection();
}

void IconData::toggleMirror()
{
    if(!myData)
    {
        return;
    }

    myData->setMirrored(!myData->getMirrored());
    updateSelection();
}

//--------------------------------------------------------------------------------------------------

IconWithData::IconWithData(QWidget* parent) :
    Icon(parent), IconData()
{
}

IconWithData::~IconWithData()
{
}

const QPixmap* IconWithData::getPixmap() const
{
    return Icon::pixmap();
}

void IconWithData::updateSelection()
{
}

void IconWithData::updatePixmap(const QPixmap* pixmap)
{
    Icon::setPixmap(pixmap, true, true);
}

আবার, একটি নতুন উত্স / শিরোলেখীর জুড়ি যুক্ত করুন এবং সেখানে "সবেমাত্র" কাজ করেছেন আইকনভিথডাটা ক্লাসের ভারব্যাটিকে কাট / পেস্ট করুন।


0

আমার কেসটি মূর্খ ছিল, ভুলের "পরে আমার অতিরিক্ত ছিল #includeএবং অনুমান কী?

undefined reference to vtable!

ভার্চুয়াল ফাংশনগুলিতে মন্তব্য করার জন্য কয়েক ঘন্টার জন্য আমি আমার মাথা এবং মুখের প্যাচিং করে যাচ্ছি কিনা দেখার জন্য এবং শেষ পর্যন্ত অতিরিক্ত সরিয়ে দিয়ে " সবকিছু ঠিক করে দেওয়া হয়েছিল! এই ধরণের জিনিসগুলির সত্যই সংকলন ত্রুটির ফলে লিঙ্ক ত্রুটি নয় in

অতিরিক্ত দ্বারা ", আমি বলতে চাই:

#include "SomeHeader.h""

0

আমার ক্ষেত্রে, আমার পার্সন নামে একটি বেস ক্লাস এবং ছাত্র এবং অধ্যাপক নামে দুটি উত্পন্ন ক্লাস ছিল।

আমার প্রোগ্রাম কিভাবে সংশোধন করা হয়েছে ছিলেন 1. আমি তৈরি সব ফাংশন বেস ক্লাসে Pure Virtual. 2. আমি ব্যবহৃত সব ভার্চুয়াল destructors যেমনdefault ones.


-3

আমি এই ত্রুটিটি পেয়েছি কারণ একটি নির্মাণকারীর যুক্তির নাম শিরোনাম ফাইল এবং বাস্তবায়ন ফাইলে পৃথক। কনস্ট্রাক্টরের স্বাক্ষর

PointSet (const PointSet & pset, Parent * parent = 0);

এবং বাস্তবায়নে আমি যা লিখেছি তা দিয়েই শুরু হয়েছিল

PointSet (const PointSet & pest, Parent * parent)

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


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