لماذا أحصل على خطأ تجزئة عند استدعاء طريقة افتراضية في هذا الرمز؟

StackOverflow https://stackoverflow.com/questions/710607

سؤال

مازلت أتعلم لغة C++؛كنت أحاول معرفة كيفية عمل تعدد الأشكال وحصلت على خطأ تجزئة عند استدعاء طريقة افتراضية.

(ملحوظة:لم أضع علامة على المدمر باعتباره افتراضيًا، كنت أحاول فقط معرفة ما سيحدث.) وإليك الرمز:

#include <iostream>

using namespace std;

class Base
{
protected:
  char *name;

public:
  Base(char *name)
  {
    cout << name << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

أيضًا، إذا كانت لديك أي نصائح أخرى بخصوص استخدام الميراث وتعدد الأشكال بشكل عام لشخص يعرف هذه المفاهيم في Java، فيرجى إبلاغي بها.شكرًا لك!

هل كانت مفيدة؟

المحلول

واسم - وunintialized في قاعدة

وأيضا لديك مشكلة أخرى:

  Base c = Child("2");

وأنا لا أعتقد أنه ما تريد. سوف التعليمات البرمجية إنشاء مثيل من قاعدة من الطفل مسبوكة. ولكن أعتقد أنك تريد العمل مع المثال الطفل بناء على واجهة قاعدة. يجب عليك بدلا من ذلك كتابة:

  Base *c = new Child("2");

وأيضا، لتجنب الأخطاء في المستقبل، أن يعلن المدمر في قاعدة كما الظاهري.

نصائح أخرى

وأنت لا التهيئة متغير قاعدة nenber - يجب أن يكون منشئ الأساسي الخاص بك:

Base(char * aname) : name( aname )
  {
    cout << name << ": Base class cons" << endl;
  }

وفضلا عن ذلك، عندما تقول

Base b = Child( "xxx" );

وبعد ذلك سيتم شرائح المثال الطفل وصولا الى قاعدة، والتي ربما لا ما تريد.

وأنا لا أعتقد أنك تعيين شار عضو * الاسم إلى أي شيء في ctors الخاص بك.

والطفل :: يمكن التخلص () لن يتم استدعاء أسلوب - ج هو متغير من نوع قاعدة، وليس مؤشر أو إشارة، لذلك سوف يتم التحقق من أساليب الافتراضية

Base * c = new Child("1");
c->disp();
delete c;

وسيدعو الطفل :: يمكن التخلص ().

قف هناك.

هناك بعض المشاكل، ولكن من المحتمل أن يكون segfault الخاص بك هو أنك تمر بـ char* -- وهو مجرد مؤشر، ثم يحاول ذلك cout فيه disp().المشكلة هي أن هذا المؤشر لا يعيش فيه disp(), ، إنه يعيش في main().ربما تريد إما نسخ ملف char*, ، او استعمل std::string.القيام بذلك بهذه الطريقة لن ينجح.

يحرر:

انظر تحرير 2

لا يمكنك فقط تعيين اسم للفصل الدراسي name عامل.إذا قمت بذلك، فستحصل على نتائج غير متوقعة - ومن المحتمل أن تظل مخطئًا.يتذكر:في C/C++، يتم تحديد نطاق الكائنات محليًا ما لم يتم تخصيصها في الكومة.في هذه الحالة، في ctor الخاص بك، قد ترغب في القيام بشيء مثل:

this->name = new char[ strlen( name ) + 1 ];
strcpy( this->name, name );

وفي المدمر، ستحتاج إلى القيام بشيء مثل:

delete [] this->name;

ملحوظة:قد يكون بناء الجملة الخاص بي خاطئًا تمامًا، وأنا أدرك أن الكود أعلاه غير آمن بطبيعته لأنك لا تتحقق من char* للتأكد من أنها ليست فارغة، وأنك لا تتحقق من القيمة المرجعة لـ new. ومع ذلك، هذا يجب أن يبدأ.

تحرير 2:أنا أقف بشكل صحيح.يتم التعامل مع القيم الحرفية للسلسلة على أنها تخزين ثابت، وبالتالي تستمر طوال مدة البرنامج. مع ذلك, أعتقد أن الدرس مهم: بشكل عام، عند عدم التعامل مع سلسلة حرفية, ، بتمرير مؤشر (أو مصفوفة، وما إلى ذلك)، تحتاج إلى تخصيص مساحة تخزين له ونسخه بعمق.تحتاج أيضًا إلى إلغاء التخصيص بشكل مناسب عند تدمير الكائن المذكور.

وهناك بعض المشاكل هنا. وأول شيء هو بك المدمر الفئة الأساسية يجب أن يكون الظاهري. وإلا سوف يكون دائما ودعا بك المدمر الفئة الأساسية حتى لو كان يشير إلى كائن مشتقة. الثاني هو يجب عدم تعيين الكائن فئة مشتقة من وجوه الفئة الأساسية. وهذا ما يسمى تشريح جسم. لذلك، ينبغي أن يتم التعيين من خلال المؤشر أو مرجع.

ويحدث المشكلة تجزئة لأنه يحتوي على قيمة القمامة. تحتاج إلى تهيئة في منشئ.

لديك بعض المشاكل مع التعليمات البرمجية.

أولا، والسبب الخاص بك الحصول على segfault، وتنفيذ المنشئ قاعدة يأخذ المعلمة التي تحمل الاسم نفسه باعتباره واحدا من "المتغيرات عضو الفئة:

class Base
{
protected:
  char *name;

public:
  Base(char ***name**)
  {
    cout << name << ": Base class cons" << endl;
  }

والمعلمة والمنشئ ل'اسم' <لأ href = "http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp؟topic=/com.ibm.xlcpp8l.doc/language/ref /name_hiding.htm "يختلط =" نوفولو noreferrer "> يخفي متغير الفئة 'عضو في نفسه، إدارة مخاطر المؤسسات ... الاسم.

وثانيا، كنت تشريح وجوه الخاص بك هنا:

int main()
{
  //Base b;
  //b.disp();
  Base c = Child("2");
  c.disp();
}

'ج' هو من نوع قاعدة، وتحاول تعيين الطفل إليها. سيتم شرائح كل من الاشياء التي هي فريدة من نوعها لطفل خارج عند تعيين ogbject إلى الفئة الأساسية.

وهنا هو الرمز الذي يحدد كل من هذه المشاكل:

#include <iostream>
#include <string>

using namespace std;

class Base
{
protected:
    std::string name_;

public:
  Base(char *name)
      : name_(name) {
    cout << name_ << ": Base class cons" << endl;
  }

  ~Base()
  {
    cout << name_ << ": Base class des" << endl;
  }

  virtual void disp();
};

void Base::disp()
{
  cout << name_ << ": Base disp()" << endl;
}

class Child : public Base
{
public:
  Child(char *name):
    Base(name)
  {
    cout << name_ << ": Child class cons" << endl;
  }

  ~Child()
  {
    cout << name_ << ": Child class des" << endl;
  }

  virtual void disp()
  {
    cout << name_ << ": Child disp()" << endl;
  }
};


int main()
{
  //Base b;
  //b.disp();
  Base * c = new Child("2");
  c->disp();
  delete c;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top