מושג הממשק
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C של Coddy. שיעור 40 מתוך 61.
עד כה, המבנים שלנו שילבו יחד נתונים והתנהגות: למשל, שם לצד מצביע לפונקציה. אבל מה אם מבנה יכיל רק מצביעים לפונקציות? כך נוצר משהו רב־עוצמה: ממשק.
ממשק מגדיר אילו פעולות זמינות בלי לציין HOW הן פועלות. זהו חוזה שאומר: "כל אובייקט שמממש את הממשק הזה חייב לספק את הפונקציות האלה."
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;המבנה ILogger אינו מכיל דבר מלבד מצביע לפונקציה. אין לו נתונים משלו. הוא מתאר התנהגות בלבד. הקידומת "I" היא מוסכמה נפוצה המציינת שמדובר בממשק.
כל קוד שמקבל ILogger אינו תלוי במקום שאליו נשלחת הודעת היומן. אפשר להדפיס אותה למסוף, לכתוב אותה לקובץ או לשלוח נתונים דרך רשת. הקוד הקורא רק יודע שהוא יכול לקרוא ל־log:
void process(ILogger* logger, const char* msg) {
logger->log(msg); // אנחנו לא יודעים איך הוא מבצע רישום ביומן
}ההפרדה הזאת היא המהות של פולימורפיזם. הפונקציה process פועלת עם כל מימוש של מתעד. אפשר להחליף התנהגויות בלי לשנות את הקוד של הפונקציה. בשיעור הבא תיצור מימושים קונקרטיים שמקיימים את החוזה של הממשק הזה.
אתגר
קלנבנה ממשק ICalculator: מבנה שמכיל רק מצביעים לפונקציות, ומגדיר אילו פעולות כל מחשבון חייב לתמוך בהן, בלי לציין כיצד הן פועלות.
תיצרו שני קבצים כדי לארגן את הקוד:
calculator.h: הגדירו כאן את הממשק. צרו טיפוס של מצביע לפונקציה בשםBinaryOpשמקבל שני פרמטרים מסוגintומחזירint. לאחר מכן הגדירו מבנהICalculatorשמכיל רק שני מצביעים לפונקציות:operate(מטיפוסBinaryOp) ו-describe(מצביע לפונקציה שאינה מקבלת פרמטרים ואינה מחזירה ערך). המבנה הזה הוא ממשק בלבד. הוא אינו מכיל נתונים, אלא רק התנהגות.main.c: כללו את קובץ הכותרת וממשו פונקציות קונקרטיות שיכולות למלא את דרישות הממשק:add: מחזירה את הסכום של שני מספרים שלמיםmultiply: מחזירה את המכפלה של שני מספרים שלמיםdescribe_add: מדפיסהAdditiondescribe_multiply: מדפיסהMultiplication
ICalculator, שייכו לו פונקציות בהתאם לקלט והשתמשו בו כדי לבצע חישוב.
התוכנית תקבל שלושה קלטים: שני מספרים שלמים וקוד פעולה (1 לחיבור, 2 לכפל).
בהתאם לקוד הפעולה, שייכו ל-ICalculator את זוג הפונקציות המתאים. לאחר מכן קראו ל-describe דרך הממשק כדי להדפיס את שם הפעולה, ואחר כך קראו ל-operate כדי לחשב ולהדפיס את התוצאה.
פלט לדוגמה כאשר הקלטים הם 5, 3 ו-1:
Addition
8פלט לדוגמה כאשר הקלטים הם 4, 7 ו-2:
Multiplication
28התובנה המרכזית היא שמבנה ICalculator שלכם מגדיר חוזה: כל קוד שמשתמש בו יודע שאפשר לקרוא ל-describe ול-operate, בלי לדעת אילו פונקציות מסוימות שויכו אליהם. זכרו להשתמש בשומרי הכללה בקובץ הכותרת.
נסו בעצמכם
#include <stdio.h>
#include "calculator.h"
// TODO: ממשו את הפונקציה add
// מחזירה את הסכום של שני מספרים שלמים
// TODO: ממשו את הפונקציה multiply
// מחזירה את המכפלה של שני מספרים שלמים
// TODO: ממשו את הפונקציה describe_add
// מדפיסה "Addition"
// TODO: ממשו את הפונקציה describe_multiply
// מדפיסה "Multiplication"
int main() {
int num1, num2, op_code;
scanf("%d", &num1);
scanf("%d", &num2);
scanf("%d", &op_code);
// TODO: צרו מופע של ICalculator
// TODO: בהתאם ל-op_code (1 עבור add, 2 עבור multiply),
// חברו את המחשבון לפונקציות המתאימות
// TODO: קראו ל-describe דרך הממשק
// TODO: קראו ל-operate דרך הממשק והדפיסו את התוצאה
return 0;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
4כימוס
המושג של מצביעים אטומיםהגדרת מבנים אטומיםפונקציות Get ו-Setאימות ב-Settersסיכום: הקופסה הסודית2אובייקטים ומתודות
מבנים כאובייקטיםמצביע 'Self'נכונות constמצביע לעומת ערךמתודות עזרחזרה: מנהל נקודות5פרויקט: חשבון בנק פשוט
הגדרת הפרויקטמימוש החשבוןתרגלו בעצמכם: קומפיילר C אונליין