מצביעים והפניות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 13 מתוך 104.
עכשיו, כשאתם מבינים זיכרון מחסנית וזיכרון ערימה, בואו נבחן את הכלים שמאפשרים לכם לעבוד ישירות עם מיקומי זיכרון: מצביעים והפניות.
מצביע שומר את כתובת הזיכרון של משתנה אחר. מצהירים עליו באמצעות * ומקבלים כתובת באמצעות &.
int value = 42;
int* ptr = &value; // ptr מכיל את הכתובת של value
std::cout << ptr; // מדפיס את כתובת הזיכרון
std::cout << *ptr; // גישה לערך דרך מצביע: מדפיס 42הפניה היא כינוי למשתנה קיים. לאחר שהיא נקשרת, היא תמיד מתייחסת לאותו משתנה. מצהירים עליה באמצעות &.
int value = 42;
int& ref = value; // ref הוא שם נוסף ל-value
ref = 100; // משנה את value ל-100
std::cout << value; // מדפיס 100הבדלים עיקריים:
| מצביעים | הפניות |
|---|---|
| יכולים להיות null | חייבות להיות מאותחלות |
| אפשר לשנות את ההקצאה שלהם | אי אפשר לשנות את ההפניה שלהן |
משתמשים ב־* כדי לגשת לערך | ניגשים לערך ישירות |
| יכולים להצביע על שום דבר | תמיד תקפות |
שניהם חיוניים להעברת אובייקטים לפונקציות ביעילות ללא העתקה, ולעבודה עם זיכרון שהוקצה בערימה. הפניות בטוחות ופשוטות יותר, בעוד שמצביעים מציעים גמישות רבה יותר כשצריך להקצות מחדש או לבדוק אם הערך הוא null.
אתגר
קלבואו נבנה מערכת פשוטה לשינוי ערכים, שמדגימה כיצד מצביעים והפניות פועלים באופן שונה כשמשנים נתונים.
תיצרו שני קבצים כדי לארגן את הקוד שלכם:
ValueOps.h: הגדירו שלוש פונקציות שמשנות ערכים של מספרים שלמים בדרכים שונות:doubleByPointer(int* ptr): מקבלת מצביע ומכפילה את הערך שעליו הוא מצביעtripleByReference(int& ref): מקבלת הפניה ומשלשת את הערךswapValues(int* a, int* b): מקבלת שני מצביעים ומחליפה בין הערכים שעליהם הם מצביעים
main.cpp: קראו שני מספרים שלמים מהקלט, ואז הדגימו שימוש במצביעים ובהפניות:- הדפיסו את הערכים המקוריים:
"Original: <first> <second>" - השתמשו ב-
doubleByPointerעל הערך הראשון, ואז הדפיסו:"After double: <first>" - השתמשו ב-
tripleByReferenceעל הערך השני, ואז הדפיסו:"After triple: <second>" - השתמשו ב-
swapValuesכדי להחליף בין שני הערכים, ואז הדפיסו:"After swap: <first> <second>"
- הדפיסו את הערכים המקוריים:
כשקוראים לפונקציות עם מצביעים, זכרו להשתמש באופרטור קבלת הכתובת (&) כדי להעביר את הכתובת של המשתנה. הפניות פועלות באופן טבעי יותר — פשוט העבירו את המשתנה ישירות.
כללו את קובץ הכותרת שלכם ב-main.cpp באמצעות #include "ValueOps.h".
נסו בעצמכם
#include <iostream>
#include "ValueOps.h"
using namespace std;
int main() {
// קרא שני מספרים שלמים מהקלט
int first, second;
cin >> first;
cin >> second;
// הדפס את הערכים המקוריים
cout << "Original: " << first << " " << second << endl;
// TODO: השתמש ב-doubleByPointer על הערך הראשון (העבר את הכתובת באמצעות &)
// TODO: הדפס לאחר ההכפלה ב-2
// TODO: השתמש ב-tripleByReference על הערך השני (העבר את המשתנה ישירות)
// TODO: הדפס לאחר ההכפלה ב-3
// TODO: השתמש ב-swapValues כדי להחליף בין שני הערכים (העבר את הכתובות באמצעות &)
// TODO: הדפס לאחר ההחלפה
return 0;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP
קבצים חיצונייםבנייה וקומפילציה של C++קובצי Header וקובצי מקורמרחבי שמות והיקףמבוא ל-OOP ב-C++מחלקות לעומת אובייקטיםמצביע thisמתודות (פונקציות איבר)תכונות (חברי נתונים)יסודות הבנאים וההורסיםסיכום – מחשבון פשוט4מאפייני מחלקה
חברי מופע לעומת חברים סטטייםגטרים וסטריםפונקציות איבר קבועותמילת המפתח mutableמתודות ומשתנים סטטייםפונקציות ומחלקות ידידותסיכום – מנהל חשבונות בנק7ירושה
ירושה בסיסיתרמות גישה בירושהסדר הקריאות לבנאי ולמפרקדריסת מתודותפונקציות וירטואליות ו־VTableירושה מרובהירושה וירטואליתסיכום – היררכיית עובדים2ניהול זיכרון
זיכרון Stack לעומת Heapמצביעים והפניותזיכרון דינמי (new/delete)מצביעים חכמים ב-C++RAII ב-C++סיכום – מנהל מערכים דינמיים5כימוס
מצייני גישה ב-C++מצייני גישה לעומקהסתרת מידעמבנה לעומת מחלקהמחלקות מקוננות ופנימיותסיכום – מערכת רשומות תלמידים8רב־צורתיות
רב־צורתיות בזמן קומפילציה לעומת בזמן ריצההעמסת פונקציותפונקציות וירטואליות — מבט נוסףפונקציות וירטואליות טהורותמחלקות מופשטותתכנון ממשקים ב־C++המרה דינמית ו־RTTIסיכום — מחשבון צורות3בנאים והורסים
בנאי ברירת מחדלבנאי עם פרמטריםבנאי העתקהבנאי העברהרשימות אתחול בבנאיםבנאים מאציליםמעמיקים בנושא הורסיםכלל השלושה / החמישה / האפססיכום – מחלקת String6העמסת אופרטורים
מבוא להעמסת אופרטוריםהעמסת אופרטורים אריתמטייםהעמסת אופרטורי השוואהאופרטורי זרםהעמסת אופרטור השמההעמסת האופרטורים [] ו־()אופרטורים להמרת טיפוסיםסיכום – מחלקת Matrix9תבניות
תבניות פונקציהתבניות מחלקההתמחות תבניותתבניות ארגומנטים משתנותיסודות SFINAE ותכונות טיפוסיםסיכום – מכל גנריתרגלו בעצמכם: קומפיילר C++ אונליין