שאלה ב C++

1אברהם

New member
שאלה ב C++

class A { protected: int data1,data2; public: A(void *p){ memcpy(this,p,sizeof(*this)); } virtual func1(); virtual func2(); };​
כשהקונסקטור מקבל מצביע לאוביקט מאותו סוג אז אין בעיה. אבל אם המצביע הוא למשל למערך של אפסים בגודל המתאים אז התוכנית נופלת, ומסתבר שזה בגלל שלא רק data1 data2 מתאפסים אלה גם הטבלה של מצביעי virtual functions . איך אני יכול לממש קונסטרקטור העתקה מבלי שאדרוך על הטבלה הזו. היכן נמצאת הטבלה הזו בזיכרון האוביקט ( בהתחלה, בסוף...) ? איך אני יכול לקבל את גודלה בזמן ריצה?
 

selalerer

New member
++C שפה יפה, למה אתה מנסה להרוס

אותה? אם אתה רוצה לעשות בנאי מעתיק, אז פשוט תעשה ככה:
class B { private: int data1,data2; public: B(B &obj) { B::data1=obj.data1; B::data2=obj.data2 } };​
אם אתה רוצה משהו אחר, אז תסביר את עצמיך יותר טוב ונמצא פתרון יותר מובנה ומהאסון הפוטנציאלי הזה שניסית לעשות.
 

1אברהם

New member
מצאתי פתרון יותר טוב לדעתי

class B { private: int data1,data2; public: B(void *p) { *this=*((B*)p); } };​
הבעיה בפתרון שלך שיש צורך בהרבה הצבות ( כמספר ה data member באוביקט ) וזה מן הסתם לוקח יותר זמן ויותר קוד . ואם אני אוסיף\אחסיר data members אני לא צריך לשנות את הקונסטרקטור חוץ מזה אני צריך שהפרמטר לקונסטרקטור יהיה מצביע מסוג void ( ולא רפרנס ) כי הוא מצביע לזיכרון שניטען מקובץ , ואת הcasting אני חושב שעדיף להחביא בתוך האוביקט . אני מניח שהמימוש של ההשמה היחידה שכתבתי הוא גם משהו כמו memcpy ( ולכן מהיר ) רק שהוא מעתיק ללא טבלת הפונקציות הוירטואליות. האם גם פתרון זה מכיל אסון פוטנציאלי ?
 

vinney

Well-known member
זה לא פתרון טוב בכלל

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

1אברהם

New member
לא הבנתי

למה זה לא טוב ? מה הכוונה "מתודה להעתקה"? דרך אגב בדקתי את זה וזה עובד
 

voguemaster

New member
בפשטות

ההשמה שביצעת שקולה ל-memcpy כמעט, בעבודה בברירת מחדל. למעשה ההשמה שלך (שכתובה בצורה ממש לא יפה אגב) שקולה לביטוי:
B = A;​
מה שאוטומטית קורא ל-assignment operator עבור המחלקה. כשאתה לא נותן מימוש של assignment operator, הקומפיילר מייצר עבורך אחד שמבצע bitwise copy של האובייקט. לכן, כן, זה עובד. אבל לא, זה לא פיתרון טוב.
 

1אברהם

New member
מה לא יפה בהצבה

*this=*((B*)p);​
בעיני זה נראה מאד יצירתי יש אפשרות אחרת ?
 

vinney

Well-known member
זה אולי יצירתי

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

selalerer

New member
מה עם מצב שהmember שלך הוא מצביע?

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

1אברהם

New member
גם כאן אני מגדיר מה בדיוק יקרה

אני קודם מעתיק את האוביקט כמו שהוא ביט לביט ואח"כ אם צריך מטפל באלו שצריכים טיפול מיוחד לדוגמה:
class B { private: int data1,data2; CFrameWnd *pwnd; public: B(void *p) { *this=*((B*)p); pwnd=new CframeWnd(); pwnd->Create(..... } };​
וכך אני חוסך הרבה הצבות. אני גם לא בטוח שהקומפילר יעשה אופטימיזציה להצבות גם אם אם יהיו לפי הסדר שהוכרזו ( ואם אני אשנה את הסדר מאוחר יותר )
 

Moridin

New member
אובייקט ב-C++

הוא בהרבה מקרים יותר מסכום איבריו, כפי שכבר גילית. על copy constructor תוכל לקרוא כאן: http://www-h.eng.cam.ac.uk/help/tpl/languages/C++/Thinking_in_C++/tic0119.html
 
זה אפשרי רק באובייקט POD

כאשר POD הוא Plain Old Data ולצורך העניין struct של C (אולי עוד כמה פונקציות טריויאליות). בכל מקרה שיטת האיתחול הזאת מזמינה צרות. אל תעתיק אובייקטים עם memcpy !!! לא לכך נועדה הפונקציה הזאת. בנוסף הממשק שלך נראה לקוי. למה שתאתחל אובייקט מפוינטר *void ? זה מתכון לעוד בלגן. אחד הדברים שבהם ++C יותר קפדנית מ-C הוא static type checking, עם האיתחול הזה הכל מתפקשש. טבלת הפונקציות הוירטואליות היא סטטית לכל התוכנית כאשר האובייקט שלך מכיל מצביע אליה. אל תניח שאתה יודע היכן המצביע הזה ב-layout של האובייקט משום שזה שונה מקומפיילר לקומפיילר ואפילו בין גרסאות שונות של אותו קומפיילר. אם אתה רוצה למרות הכל לבצע העתקה מבלי לירות לעצמך ברגל אפשר כך:
class MyClass { private: struct POD_Data { // put data here }; POD_Data my_data; public: MyClass(void* data) { memcpy(&my_data, data, sizeof(POD_Data)); } // etc };​
 

1אברהם

New member
הסיבה שההתחול נעשה מ void*

( אפשר גם * BYTE אולי) זה בגלל שהוא מצביע לזיכרון שניטען מתוך קובץ . בעצם המטרה כאן היא לשמור ולשחזר אוביקטים מקובץ. יש עוד פונקציה ( dump ) שתפקידה הפוך: לשפוך את תוכן האוביקט לזיכרון ( שאח"כ נשמר לקובץ ) והוא נראה ככה
class B { private: int data1,data2; CFrameWnd *pwnd; public: B(void *p) { *this=*((B*)p); pwnd=new CframeWnd(); pwnd->Create(..... } void dump(void *p) { *((B*)p)=*this; } };​
 
תהיה לי בריא

לא ככה עושים dump ולא ככה מאתחלים מ-dump. אני שם לב שאתה משתמש ב MFC אז מדוע לא להשתמש ב-Serialization של MFC? אין צורך להמציא את הגלגל. אם למרות הכל אתה רוצה לממש בעצמך, עשה זאת כפי שהראיתי לך למעלה. תבודד את המידע שאתה שומר/טוען לתוך struct פשוט. בהצלחה
 

1אברהם

New member
קיבלתי לגבי <<

class B { private: int data1,data2; CFrameWnd *pwnd; public: B(); B(void *p) { *this=*((B*)p); pwnd=new CframeWnd(); pwnd->Create(..... } virtual void operator >> (void *p) { *((B*)p)=*this; } }; #define NUMOBJ 10 #define OBJMAXSIZE 1000 void main() { B o[NUMOBJ]; ...... // save to memory int n; BYTE pmem=new BYTE[NUMOBJ*OBJMAXSIZE ]; for(n=0;n<10;n++){ o[n]>>pmem; pmem+=OBJMAXSIZE ; } // save to file with handle h DWORD u; WriteFile(h,pmem,NUMOBJ*OBJMAXSIZE,&u, 0); delete pmem; }​
לגבי >> לא נראה לי שצריך אותו
 
למעלה