עזרה בהקצאה ב C++. - תכנות - HWzone פורומים
עבור לתוכן
  • צור חשבון

עזרה בהקצאה ב C++.


Chaos

Recommended Posts

שלום לכולם.

לפניכם קטעי שורות אשר מטרתם הקצאת מערך מסוג פוינטר לסטודנט, ואחר-כך הקצאת סטודנט בכל אחד מאיברי המערך.

Student **StudentTemp;
StudentTemp=new Student*[size];
StudentTemp[i]=new Student;

ההקצאה הנ"ל לא עובדת, ולאחר הרצת Debugger התגלתה טעות בהקצאה (Segmentation) בשורה שלישית. יש למישהו רעיון מה יכולה להיות הבעייה?

תודה מראש, קובי.

קישור לתוכן
שתף באתרים אחרים

טוב, אני כנראה אצטרך להעתיק לכם את הלולאה כולה, ואת ה classes הקשורים.

נעשו שינויים, זו התוכנית המעודכנת, אינני בטוח אם הבעייה היא בקטע הנ"ל, או בפונקציה שאחריו, נראה כי הבעייה דווקא בקטע הקוד הקטנטן הנ"ל, אשר נמצא ב main:

Person **pPersonArr=NULL;
*pPersonArr=Get_Updates();

Person* Get_Updates()
{
ifstream file1("AllStudents.txt"), file2("AllEmployees.txt");
if ((file1==NULL) || (file2==NULL))
{
cout<<"Could not link to files."<<endl;
exit(1);
}
int i, j, size1, size2;
file1>>size1;
file2>>size2;
Person** PersonTemp= new Person*[size1+size2];;
char name[MAX_LETTERS], username[MAX_LETTERS], password[MAX_LETTERS];
long course_numbers[5];
int grades[10], year=0;
for (i=0; i<size1; i++)
{
file1>>name>>username>>password>>year;
for (j=0; j<5; j++)
{
file1>>course_numbers[j];
file1>>grades[2*j]>>grades[2*j+1];
}
PersonTemp[i]=new Student(name, username, password, year, course_numbers, grades);
}
char position[MAX_LETTERS];
long course_number=0;
for (j=i; j<size1+size2; j++)
{
file2>>name>>username>>password>>position>>course_number;
PersonTemp[j]=new Employee(name, username, password, position, course_number);
}
PersonTemp[size1+size2]=NULL;
file1.close();
file2.close();
return *PersonTemp;
}

והקטעים החשובים בכל class:

Person::Person(char name[MAX_LETTERS], char username[MAX_LETTERS], char password[MAX_LETTERS])
{
strcpy(m_pName, name);
strcpy(m_pUserName, username);
strcpy(m_pPassword, password);
}

Student::Student(char name[MAX_LETTERS], char username[MAX_LETTERS], char password[MAX_LETTERS], int year, long course_numbers[5], int grades[10])
:Person(name, username, password)
{
m_pYear=year;
for (int i=0; i<5; i++)
m_pCourseNumber[i]=course_numbers[i];
for (i=0; i<10; i++)
m_pGrades[i]=grades[i];
}

Employee(char name[MAX_LETTERS], char username[MAX_LETTERS], char password[MAX_LETTERS], char position[MAX_LETTERS], long course_number)
:Person(name, username, password)
{
strcpy(m_pPosition, position);
m_pCourseNumber=course_number;
}

הערה:

כמובן ש Student ו Employees יורשות את Person.

אודה מאוד על כל עזרה שתבוא, תודה מראש, קובי.

עריכה: אני מצטער של כך שאין הזחות, משום מה אינני מצליח להעתיק קטעי קוד עם ההזחות. תדוה על ההתחשבות.

קישור לתוכן
שתף באתרים אחרים

כמובן שהעברתי רק את הקטעים הרלוונטיים, המשתנים של כל class הוקצאו כנדרש, והרי התוכנית כולה ערכה קומפילציה.

בכל מקרה, נראה לי כי הצלחתי להתגבר על הבעייה עם פתרון די פשוט,

במקום השורה השנייה ב main הייתי צריך לרשום:

pPersonArr=Get_Updates();

ולהחזיר ערך של Person** ב Get_Updates.

אגב, לאחר מכן אני נדרש לבצע פעולות על הסטודנטים והעובדים במערך, איך אני ניגש לפונקציות שלהן, אשר אינן ב Person, דרך המערך הזה?

קישור לתוכן
שתף באתרים אחרים

קודם כל אתה צריך לדעת את ההבדל בין סוג מצביע לסוג הקצאה. סוג מצביע הוא סוג המשתנה שהגדרת בתוכנית, במקרה שלך person, וסוג ההקצאה זהו הקלאס שאותו הקצאת, במקרה שלך עובד וסטודנט.

ועכשיו ישנן 2 פתרונות:

1) late binding עם פונ virtual. כשאתה מריץ את התוכנית, איפה שאתה מריץ אותה בודקת מה סוג ההקצאה ומבצעת את הפונ המתאימה בהתאם. יתרון חשוב הוא הקלות בשימוש בסוג פתרון זה, וחיסכון במשתנה שיוסבר בתהליך הבא. החסרון הוא הזמן ריצה הארוך יחסית של ריצת התוכנית, מכיוון שכל פעם שתקרא לפונ, המחשב יצטרך לבדוק מה סוג ההקצאה, ו"ליצור" לה את הפונ המתאימה. המילה virtual תופיע במחלקת האב לפני שם הפונ ותמומש שם וחלק מהמחלקות היורשות. ישנה עוד סוג פונ virtual שהיא ללא מימוש במחלקת האב והיא תוגדר ע"י ; בסוף(או משהו עם 0 אני כבר לא זוכר לצערי) ואותן אתה חייב לממש בכל המחלקות היורשות.

2) casting - אתה יכול לבצע casting למשתנה שלך, וכך הקומפיילר ידע באיזו פונ להשתמש. כמובן שאתה צריך לשמור איפשה את סוג ההקצאה(סטודנט או עובד במקרה שלך).

קישור לתוכן
שתף באתרים אחרים

ראשית, תודה רבה.

שנית, בעניין הפונקציות הוירטואליות וקישור מאוחר, אני אוכל לגשת לפונקציה ב Student (לדוגמה), דרך המערך של מצביעים ל Person, רק אם היא תוצהר גם ב Person כפונקציה וירטואלית. אני מעוניין לגשת לפונקציות אשר אינן מופיעות ב Person אלא מיוחדות ל Student בלבד. האם יש אפשרות לעשות זאת דרך המערך?

אם כן - כיצד?

אם לא - האם ישנה דרך אחרת שאוכל לעשות זאת?

בתודה מראש, קובי.

עריכה:

אני מקבל את השגיאות קישור הבאות:

Linking...

Main.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall Person::Add(void)" (?Add@Person@@UAEXXZ)

Main.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall Person::Private_Details_Menu(void)" (?Private_Details_Menu@Person@@UAEXXZ)

Main.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall Person::Private_Details(void)" (?Private_Details@Person@@UAEXXZ)

Main.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall Person::List(void)" (?List@Person@@UAEXXZ)

Debug/Main.exe : fatal error LNK1120: 4 unresolved externals

Error executing link.exe.

Main.exe - 5 error(s), 0 warning(s)

יש למישהו מושג מה הבעייה?

קישור לתוכן
שתף באתרים אחרים

השגיאה אומרת שהקומפיילר לא מצא את המימוש של הפונקציות Add, Private_Details_Menu, Private_Details ו- List של Class Person.

אלא אם הגדרת אותן כ- pure virtual ב- person - כלומר למשל

(בתוך הגדרת Person)

virtual void List() = 0

הקומפיילר יחפש את הפונקציה וייצעק עליך כשהוא לא מוצא אותה.

עוד סיבה שהוא לא מוצא אותה יכולה להיות שקובץ ה- cpp לא מלונקג'.

ב- C++ אם חייבים לבצע downcast, עדיף לעשות את זה עם dynamic_cast, שמחזיר לך null אם הוא לא הצליח.

יש לזה עלות בביצועים, ואתה חייב לקמפל עם RTTI support.

דרך פחות טובה והרבה פחות בטוחה לעשות את זה הוא פשוט cast של המצביע.

ברוב המקרים יש דרכים לעקוף את הצורך ב- downcast.

קישור לתוכן
שתף באתרים אחרים

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

×
  • צור חדש...