שאלה על this בCPP

ASP zone

New member
שאלה על this בCPP

איך אני עושה שהכתובת של this תהיה מאוכסן בפוינטר? קוד:
class b { ... public: b(a *p_tothis) {p_tothis->cc++; } class a { int cc; b *o; public: a() {o = new b(&this);} };​
קטע קוד כזה אמור לעבוד? כי הוא לא.
 

אמיר ט

New member
המ...

טוב נתחיל בזה שיהיה מאד נחמד אם פעם הבאה תצטרף את השגיאות שאתה מקבל. ועכשיו לדברים לא נכונים במה שכתבת : 1. יש לך את אובייקט B, שצריך להכיר את אובייקט A. הבעיה היא שגם A צריך להכיר את B ולכן זה בעיה להחליט מי ראשון. הפתרון לזה אולי נשמע קצת מסורבל אבל בפועל הוא דיי פשוט : בקובץ ה .h שלך תצטרך להגדיר משהו כזה :
class a; class b { ... public: b(a *p_tothis); }; class a { int cc; b *o; public: a() {o = new b(&this);} };​
עכשיו בקובץ ה .cpp אתה תשים את המימוש של הקונסטרקטור של b. מה שקורה כאן בעצם הוא שאובייקט B בעצם מכיר רק את מצביע ל a. כל עוד אנחנו לא קוראים לאף פונק' של a זה בסדר, בקובץ הcpp שלך, אתה עושה include לקובץ ה h ועכשיו אתה יכול במימושים של b להוסיף התייחסות לדברים שבאמת יש ב a (כי "עלינו" עליו בהגדרה חדשה) 2. עכשיו אחרי שמבחינה לוגית זה אמור לעבוד, אנחנו נתקלים בבעיה נוספת - אנחנו מנסים לגשת למשתנה cc של a, אבל הוא private (כמו כל משתנה באובייקט שלא הוגדר לו אחרת). אז יש לנו שני ברירות - או לעשות אותו public או לחשוף אותו באמצעות פונק' מתאימה. זהו בגדול, אלא כל הבעיות שראיתי אצלך בקוד, אני מקווה שההסבר ברור ושהבנת איך מתמודדים עם הבעיות האלה. בהצלחה.
 

® רן

New member
יש עוד בעיה לדעתי

this הוא מצביע. אתה מעביר את this&, שהוא מצביע למצביע - לא מה שהתכוונת. הפונקציה שלך אמורה לקבל *a, ואתה מעביר לה this& שהוא מטיפוס **a. תעביר פשוט את this, ללא &.
 

® רן

New member
אם אתה רוצה התייחסות רצינית

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

ASP zone

New member
הבעיה היא שאני לא יודע מה הבעיה

זה לא מתקמפל בכלל ראה למטה פירסמתי קוד מלא... עם השגיאות
 

® רן

New member
תנסה לחזור לדוגמא הראשונה שנתת

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

ASP zone

New member
הנה

שגיאות:
In file included from main.cpp:2: header.h: In member function `void b::print()': header.h:10: error: invalid use of undefined type `struct a' header.h:4: error: forward declaration of `struct a' header.h: In constructor `a::a()': header.h:20: error: no matching function for call to `b::b()' header.h:6: error: candidates are: b::b(const b&) header.h:9: error: b::b(a*) header.h: In constructor `b::b(a*)': header.h:17: error: `int a::cc' is protected main.cpp:3: error: within this context main.cpp:3: error: syntax error before `)' token main.cpp:7: error: `ob' undeclared (first use this function) main.cpp:7: error: (Each undeclared identifier is reported only once for each function it appears in.) main.cpp:9: error: returning a value from a constructor​
קוד:
main.cpp #include <cstdlib> #include "header.h" b::b(a *p_tothis) {pp = p_tothis;pp->cc = 5;) int main() { a *ob; ob->b->print(); system("PAUSE"); return 0; } header.h #include <iostream> using namespace std; class a; class b { a *pp; public: b(a *); void print() {cout << pp->cc;} }; class a : public b { protected: int cc; public: b *o; a() {o = new b(this);} };​
זה מה שעשיתי
 

® רן

New member
מצוין

בוא נעבור על השגיאות אחת אחת:
header.h:10: error: invalid use of undefined type `struct a'​
מה שצריך לזכור כאן שקומפיילר עובר על התוכנית שלך מההתחלה לסוף בצורה סדרתית, ורק פעם אחת. הוא חייב לראות הגדרה של כל פונקציה וכל מחלקה לפני שאתה משתמש בה. שורה 10 אצלך היא:
void print() {cout << pp->cc;}​
שבה אתה ניגש לאיבר cc באובייקט מטיפוס a, כאשר עדיין בשורה זו לא ראינו הגדרות לא של a ולא של cc. יש בעיה להעביר אותם לנקודה יותר מוקדמת כי אז דברים אחרים לא יעבדו. מה עושים? הפתרון הפשוט ביותר הוא בשלב זה להגדיר רק את ה prototype של הפונקציה:
void print();​
ובשלב מאוחר יותר (יכול להיות בקובץ main בסוף), לכתוב את גוף הפונקציה:
void b::print() { cout << pp->cc; }​
עכשיו לבעיה השניה, שמתייחסת לשורה הבאה:
header.h:20: error: no matching function for call to `b::b()' a() {o = new b(this);}​
כאן זה קצת יותר מסובך. שים לב שהמחלקה a שלך גם יורשת מ b וגם מכילה אובייקט b. כאשר יורשים ממחלקה, מקבלים אוטומטית העתק שלה, כך שלך בעצם יש שניים. בבנאי שלך של a יש אתחול של האיבר b, אבל אין אתחול של החלק ה b-י של a - החלק שקיבלת בירושה. למחלקה b שלך אין בנאי דפולטי (default constructor) שניתן להריץ אותו ללא פרמטרים, ולכן הפעולה נכשלת. איך מתקנים? תלוי במה שאתה מנסה לעשות. אני מניח שלא באמת התכוונת שיהיו לך שני עותקים של b בכל אובייקט a, ולכן אחד מהם מיותר. אפשרות א': לבטל את הירושה, ואז נראה לי שהכל יעבוד. אפשרות ב': לבטל את האיבר b* o בתוך a, ולהפוך את השורה הבעייתית ל:
a():b(this) {}​
זה יגרום לבנאי של a להריץ את הבנאי של החלק ה b-י שלו עם הפרמטר שרצית. הבעיה הבאה:
header.h: In constructor `b::b(a*)': header.h:17: error: `int a::cc' is protected​
לדעתי יש לך פה אי הבנה של מה זה protected. הגדרת משתנה כ protected אומרת שמחלקה יורשת יכולה לגשת אליו - מתוך אותו אובייקט בלבד! הכוונה שאם יש לך אובייקט מטיפוס a, החלק ה b-י שלו יכול לגשת לחלק ה a-י שלו, אבל רק שלו. פה יש לך אובייקט אחד שמנסה לגשת לחלקים של אובייקט אחר, וזה לא עובד. גם כאן, אתה צריך להחליט למה התכוונת, לפני שאפשר יהיה לתקן. שאר השגיאות נגרמות מכך שבשורה:
b::b(a *p_tothis) {pp = p_tothis;pp->cc = 5;)
אתה צריך לסגור אותה עם סוגריים מסולסלים - { - ולא סוגריים רגילים - (.
 

ASP zone

New member
אוקי הנה מה שעשיתי

header.h #include <iostream> using namespace std; class a; class b { a *pp; public: b(a *); void print(); }; void b::print() {cout << pp->cc;} class a { public: int cc; b *o; a() {o = new b(this);} }; main.cpp #include <cstdlib> #include "header.h" b::b(a *p_tothis) {pp = p_tothis;pp->cc = 5;} int main() { a *ob; ob->o->print(); system("PAUSE"); return 0; }
שגיאות שנשארו:
In file included from main.cpp:2: header.h: In member function `void b::print()': header.h:13: error: invalid use of undefined type `struct a' header.h:4: error: forward declaration of `struct a'​
 

ASP zone

New member
אוקי תיקון

העברתי את זה
void b::print() {cout << pp->cc;}​
לmain.cpp התוכנית רצה אבל קורסת. מכאן אין לי אפילו debug של שגיאות. אוי אני במצב גרוע. למישהו יש מושג איך פותרים את הבעית עיצוב הזאת? מישהו שמבין בDND אולי?
 

® רן

New member
ברור שהיא תקרוס

תראה את:
a *ob; ob->o->print();​
אתה מגדיר כאן מצביע, לא מאתחל אותו (ולכן הוא מכיל ערך "זבל", ומייד משתמש בו. צריך להיות:
a *ob = new a();​
 

ASP zone

New member
תודה

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

ASP zone

New member
הנה הקוד המלא והשגיאות

CSkills.hpp #ifndef _CSkills #define _CSkills #include "Act.hpp" #include "Alchemy.hpp" #include "Appraise.hpp" #include "Arcana.hpp" #include "Architecture_And_Engineering.hpp" #include "Armorsmisthing.hpp" #include "Balance.hpp" #include "Bluff.hpp" #include "Bowmaking.hpp" #include "Climb.hpp" #include "Concentration.hpp" #include "CCrafts.hpp" #include "Decipher_Script.hpp" #include "Diplomacy.hpp" #include "Disable_Device.hpp" #include "Disguise.hpp" #include "Escape_Artist.hpp" #include "Forgery.hpp" #include "Gather_Information.hpp" #include "Geography.hpp" #include "Handle_Animal.hpp" #include "Heal.hpp" #include "Hide.hpp" #include "History.hpp" #include "Intimidate.hpp" #include "Jump.hpp" #include "CKnowledges.hpp" #include "Listen.hpp" #include "Local.hpp" #include "Move_Silently.hpp" #include "Nobility_And_Royalty.hpp" #include "Open_Lock.hpp" #include "Religion.hpp" #include "CPreform.hpp" #include "CProfession.hpp" #include "Ride.hpp" #include "Search.hpp" #include "Sense_Motive.hpp" #include "Sleight_Of_Hands.hpp" #include "Spellcraft.hpp" #include "Spot.hpp" #include "Survival.hpp" #include "Swim.hpp" #include "The_Plains.hpp" #include "Trapmaking.hpp" #include "Tumble.hpp" #include "Use_Magic_Device.hpp" #include "Use_Rope.hpp" #include "Weaponsmithing.hpp" namespace D20Skills { class CSkills { public: D20Act *Act; D20Alchemy *Alchemy; D20Appraise *Appraise; D20Arcana *Arcana; D20Architecture_And_Engineering *Architecture_And_Engineering; D20Armorsmisthing *Armorsmisthing; D20Balance *Balance; D20Bluff *Bluff; D20Bowmaking *Bowmaking; D20Climb *Climb; D20Concentration *Concentration; CCrafts *Craft; // Need to check the existing ... D20Decipher_Script *Decipher_Script; D20Diplomacy *Diplomacy; D20Disable_Device *Disable_Device; D20Disguise *Disguise; D20Escape_Artist *Escape_Artist; D20Forgery *Forgery; D20Gather_Information *Gather_Information; D20Handle_Animal *Handle_Animal; D20Heal *Heal; D20Hide *Hide; D20Intimidate *Intimidate; D20Jump *Jump; D20Listen *Listen; D20Local *Local; D20Move_Silently *Move_Silently; D20Nobility_And_Royalty *Nobility_And_Royalty; D20Open_Lock *Open_Lock; D20Religion Religion; CPreform *Preform; CProfession *Profession; // Need to check the existing ... D20Ride *Ride; D20Search *Search; D20Sense_Motive *Sense_Motive; D20Sleight_Of_Hands *Sleight_Of_Hands; D20Spellcraft *Spellcraft; D20Spot *Spot; D20Survival *Survival; D20Swim *Swim; D20The_Plains *The_Plains; D20Trapmaking *Trapmaking; D20Tumble *Tumble; D20Use_Magic_Device *Use_Magic_Device; D20Use_Rope *Use_Rope; D20Weaponsmithing *Weaponsmithing; CSkills(int STR, int DEX, int CON, int INT, int WIS, int CHA); }; }; #endif CSkills.cpp #include "CSkills.hpp" using namespace D20Skills; CSkills::CSkills(int STR, int DEX, int CON, int INT, int WIS, int CHA) { Appraise = new D20Appraise(INT, 0, &this); Balance = new D20Balance(DEX, 0, &this); Bluff = new D20Bluff(CHA, 0, &this); Climb = new D20Climb(STR, 0, &this); Concentration = new D20Concentration(CON, 0, &this); Decipher_Script = new D20Decipher_Script(INT, 0, &this); Diplomacy = new D20Diplomacy(CHA, 0, &this); Disable_Device = new D20Disable_Device(INT, 0, &this); Disguise = new D20Disguise(CHA, 0, &this); Escape_Artist = new D20Escape_Artist(DEX, 0, &this); Forgery = new D20Forgery(INT, 0, &this); Gather_Information = new D20Gather_Information(CHA, 0, &this); Handle_Animal = new D20Handle_Animal(CHA, 0, &this); Heal = new D20Heal(WIS, 0, &this); Hide = new D20Hide(DEX, 0, &this); Intimidate = new D20Intimidate(CHA, 0, &this); Jump = new D20Jump(STR, 0, &this); Listen = new D20Listen(WIS, 0, &this); Move_Silently = new D20Move_Silently(DEX, 0, &this); Open_Lock = new D20Open_Lock(DEX, 0, &this); Preform = new CPreform(CHA, &this); Profession = new CProfession(WIS, &this); Ride = new D20Ride(DEX, 0, &this); Search = new D20Search(INT, 0, &this); Sense_Motive = new D20Sense_Motive(WIS, 0, &this); Sleight_Of_Hands = new D20Sleight_Of_Hands(DEX, 0, &this); Spellcraft = new D20Spellcraft(INT, 0, &this); Spot = new D20Spot(WIS, 0, &this); Survival = new D20Survival(WIS, 0, &this); Swim = new D20Swim(STR, 0, &this); Tumble = new D20Tumble(DEX, 0, &this); Use_Magic_Device = new D20Use_Magic_Device(CHA, 0, &this); Use_Rope = new D20Use_Rope(DEX, 0, &this); }​
אני צריך לגשת מאובייקט אחד לאחר הנמצא במחלקה CSkills. בשביל זה אני מנסה לקחת את this...
 

selalerer

New member
ובכן:

הטעויות הללו:
Skill.hpp:31: error: syntax error before `*' token Skill.hpp:36: error: type specifier omitted for parameter `CSkills' Skill.hpp:36: error: syntax error before `*' token Skill.hpp:39: error: ISO C++ forbids declaration of `iRank' with no typeSkill.hpp:39: error: ISO C++ forbids initialization of member `iRank' Skill.hpp:39: error: making `iRank' static Skill.hpp:39: error: ISO C++ forbids in-class initialization of non-const static member `iRank'​
נראה שקשורותו בעובדה שהוא לא מכיר את המחלקה CSkills שם. תנסה לעשות הגדרה כזאת בתחילת הקובץ Skill.hpp:
class CSkills;​
זה יפתור לך חלק מהטעויות פה. באופן יותר כללי, נראה לי שיש לך פה טעות בdesign. לכל דמות יש יכולות בסיסיות מסוימות (INT, STR ....), כאשר הוא רוצה לטפס על חבל, תוכל באותו הרגע לחשב את יכולתו/סיכוייו להצליח לטפס על חבל. אני לא רואה צורך לעשות את זה מראש (חוץ ממהירות ריצת הקוד, ואת זה כדאי להשאיר לסוף הפרוייקט/מודול). כרגע יש לך המון כפילות במידע, ברגע שהדמות תעלה רמה ונאמר הזריזות שלה תשתפר, תצטרך לחשב מחדש את כל היכולות של הדמות שקשורות בזריזות, מיותר לחלוטין, תוכל לחשב יכולת של דמות כל פעם שהיא רוצה לעשות את הפעולה הזאת. זה רק מעיון כללי ביותר בקוד, אבל ככה זה נראה במבט ראשון.
 

ASP zone

New member
אני עשיתי את זה ככה כי

אני רוצה שהמיומנויות יהיו ניתנות לשינוי במהירות. מה שאתה מדבר עכשיו הוא סיוט מבחינת ידידותיות למתכנת. ואני יודע שאני אצטרך לעשות זאת. יש לך רעיון לשפר? חוץ מהחישוב מחדש
 

ilankt

New member
בהצלחה במשחק

לפי מה שראיתי אתה משקיע כ"כ במנוע של המשחק, רק חבל שהוא יהיה טקסטואלי... כשיהיה משהו שאפשר להריץ תעדכן פה
 

ASP zone

New member
אממ נכון הוא יהיה טקסטואלי

זה רק כי אני לא יודע OPENGL אוDIRECT 3D וגם אם כן אין לי מי שיעשה גרפיקות. אני אשמח לפרסם כאן.
 
למעלה