void aFoo1()

Download Report

Transcript void aFoo1()

‫תכנות מכוון עצמים ו‪++C -‬‬
‫יחידה ‪02‬‬
‫העמסת פונקציות‪ ,‬ערכי ברירת מחדל‪ , enum ,‬קימפול מותנה‬
‫קרן כליף‬
!‫נכון שזה נכון?? אז די‬
http://programmingpalace.files.wordpress.com/2011/12/smokingwarningforsoftwareengineers.jpg
2
Keren Kalif
© Keren Kalif
2
‫ביחידה זו נלמד‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪3‬‬
‫העמסת פונקציות‬
‫ערכי ברירת מחדל לפונקציות‬
‫‪enum‬‬
‫בעיית ‪'include‬ים כפולים‬
‫‪© Keren Kalif‬‬
‫העמסת פונקציות‬
‫)‪(Functions Overloading‬‬
‫‪ ‬בשפת ‪ ++C‬ניתן להגדיר כמה פונקציות עם שם זהה‪ ,‬בתנאי‬
‫שהקומפיילר ידע לאיזו גירסא לפנות‬
‫‪ ‬כלומר‪ ,‬ניתן להגדיר פונקציות עם שם זהה‪ ,‬המקבלות טיפוסים‬
‫שונים‬
‫>‪#include <iostream‬‬
‫‪ ‬היתרון‪ :‬פונקציות דומות‬
‫יכולות להיות עם שם זהה‬
‫‪ ‬דוגמא‪:‬‬
‫)(‪void main‬‬
‫}‬
‫;‪int n1=3, n2=6‬‬
‫;)‪swap(n1, n2‬‬
‫;'‪char ch1='a', ch2='z‬‬
‫;)‪swap(ch1, ch2‬‬
‫‪4‬‬
‫‪© Keren Kalif‬‬
‫{‬
‫)‪void swap(int& a, int& b‬‬
‫{‬
‫;‪int temp = a‬‬
‫;‪a = b‬‬
‫;‪b = temp‬‬
‫{‬
‫)‪void swap(char& a, char& b‬‬
‫{‬
‫;‪char temp = a‬‬
‫;‪a = b‬‬
‫;‪b = temp‬‬
‫{‬
‫בעית דו‪-‬משמעות )‪(ambiguity‬‬
‫‪ ‬הקומפיילר אינו יכול להבדיל בין ‪ 2‬פונקציות הנבדלות אך ורק‬
‫בערך המוחזר‬
‫‪ ‬הסיבה‪ :‬לא בהכרח יהיה שימוש בערך המוחזר‬
‫‪ ‬דוגמא‪:‬‬
‫>‪#include <iostream‬‬
‫‪int‬‬
‫};‪foo() {return 0‬‬
‫};'‪char foo() {return 'a‬‬
‫הקומפיילר לא ידע לאיזו גרסא לפנות‪ ,‬ונקבל שגיאת ‪:ambiguity‬‬
‫‪error C2371: 'foo' : redefinition; different basic types‬‬
‫‪5‬‬
‫‪© Keren Kalif‬‬
‫)(‪void main‬‬
‫{‬
‫;)(‪foo‬‬
‫{‬
)2( (ambiguity) ‫משמעות‬-‫בעית דו‬
:‫ גם במקרה זה הקומפיילר לא ידע לאיזו גרסא לפנות‬
#include <iostream>
#include <iostream>
‫דוגמא תקינה‬
void foo(double d) {}
void foo(float f) {}
void main()
{
int x=3;
foo(x);
{
error C2668: 'foo' : ambiguous
call to overloaded function
x ‫הקומפיילר לא יודע אם להמיר את‬
float -‫ או ל‬double -‫ל‬
void foo(double d) {}
void foo(float f) {}
void main()
{
double d = 5.2;
float f = 7.3f;
foo(d);
foo(f);
}
‫ אלא של אופן‬,‫ אינה בעיה של הפונקציות‬ambiguity -‫בעיית ה‬
‫משמעי לאיזו גרסא לפנות‬-‫ שאינו מורה לקומפיילר באופן חד‬,‫הקריאה‬
© Keren Kalif
6
‫ערכי ברירת מחדל‬
‫)‪(default values‬‬
‫‪ ‬בשפת ‪ ++C‬ניתן לתת ערך ברירת מחדל לפרמטרים האחרונים‬
‫שהפונקציה מקבלת‪ ,‬ובכך יהיה ניתן בשימוש להחסיר ארגומנטים‬
‫>‪1. #include <iostream‬‬
‫אלו‬
‫;‪2. using namespace std‬‬
‫‪ ‬התוצאה היא העמסת הפונקציה‬
‫‪3.‬‬
‫במקרה של הפרדה בין ההצהרה למימוש‪,‬‬
‫ערכי ברירת המחדל יכתבו בהצהרה‬
‫;)‪printChar(char ch='*', int times=5‬‬
‫)(‪main‬‬
‫העמסת ‪ 3‬פונקציות‬
‫במחיר מימוש של אחת ‪‬‬
‫;)‪printChar('#', 3‬‬
‫;)'@'(‪printChar‬‬
‫;)(‪printChar‬‬
‫)‪printChar(char ch, int times‬‬
‫‪7‬‬
‫)‪for (int i=0 ; i < times ; i++‬‬
‫;‪cout << ch‬‬
‫;‪cout << endl‬‬
‫‪© Keren Kalif‬‬
‫‪4. void‬‬
‫‪5.‬‬
‫‪6. void‬‬
‫{ ‪7.‬‬
‫‪8.‬‬
‫‪9.‬‬
‫‪10.‬‬
‫{ ‪11.‬‬
‫‪12.‬‬
‫‪13. void‬‬
‫} ‪14.‬‬
‫‪15.‬‬
‫‪16.‬‬
‫‪17.‬‬
‫{ ‪18.‬‬
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
#include <iostream>
using namespace std;
)2( ‫ערכי ברירת מחדל‬
void printChar(char ch='*', int times=5);
void printChar(int times, char ch='*');
void main()
{
printChar('#', 3);
printChar('@');
printChar();
printChar(8);
{
‫נשים לב כי לא ניתן לתת ערך ב"מ לפרמטר‬
ambiguity ‫ משום שנקבל שגיאת‬,times
‫במידה ויקראו לפונקציה ללא פרמטרים‬
‫קריאה לפונקציה הראשונה‬
‫קריאה לפונקציה השניה‬
void printChar(char ch, int times)
}
for (int i=0 ; i < times ; i++)
cout << ch;
cout << endl;
{
void printChar(int times, char ch)
}
printChar(ch, times);
{
:‫לא ניתן היה להגדיר את את הפונקציה הבאה‬
void printChar(int times=5, char ch);
‫משום שערכי ב"מ ניתן לתת רק לפרמטרים‬
‫ הקריאה לפונקציה‬,‫ אחרת‬.‫האחרונים ברשימה‬
‫ וזה לא תקין‬printChar( , ‘*’) :‫תצטרך להיות‬
© Keren Kalif
8
‫‪enum‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪9‬‬
‫הגדרת טיפוס חדש שיכיל ערך מספרי מתוך קבוצה מוגדרת מראש‬
‫כלומר‪ ,‬הגדרת אוסף קבועים בעלי קשר לוגי‬
‫למשל‪ :‬ימות השבוע‪ ,‬אוסף צבעים‪ ,‬ערכים בוליאנים וכד'‬
‫דוגמא‪:‬‬
‫;}‪enum color{RED, YELLOW, BLUE‬‬
‫‪ ‬זוהי הגדרה של ‪ 3‬קבועים‪ ,‬הראשון מקבל באופן אטומטי את ערך‬
‫‪ ,0‬זה שאחריו את ערך ‪ 1‬וכו'‪.‬‬
‫כעת נוכל להגדיר בתוכנית משתנים מטיפוס ‪ color‬ולתת להם את‬
‫הערכים ‪RED/YELLOW/BLUE‬‬
‫‪© Keren Kalif‬‬
‫‪ - enum‬מתן ערך שגוי‬
‫‪ ‬כאשר מסתכלים בדיבגר על ערכו של משתנה מטיפוס ‪enum‬‬
‫רואים את שם הקבוע‪ ,‬ולא את ערכו‬
‫‪ ‬אם ניתן למשתנה מטיפוס ה‪ enum -‬ערך מספרי שאינו הוגדר‬
‫בקבוצת הערכים שלו‪ ,‬נראה את הערך המספרי (לא נקבל‬
‫שגיאה)‬
‫‪10‬‬
‫‪© Keren Kalif‬‬
‫הקומפיילר לא מבצע ‪ casting‬מ‪ int -‬לטיפוס‬
‫החדש‪ ,‬לכן צריך לעשות המרה מפורשת‬
enum ‫טריק לקבלת שמו של‬
enum -‫ ניתן להגדיר מערך גלובלי של מחרוזות עם שמות ה‬
‫בהתאמה לערכיהם‬
enum color{White, Black, Red, Yellow, Blue};
const char* colors[] = {"White", "Black", "Red", "Yellow", "Blue"};
void main()
{
color c = Red;
cout << "Selected color is " << colors[c] << endl;
}
© Keren Kalif
11
‫ – מתן ערכים שונים‬enum
‫ ע"י‬,‫ ניתן לכל ערך באוסף לתת ערך שאינו עוקב לערך שלפניו‬
:‫השמה‬
enum color {White=10, Black=20, Red=30, Yellow=40, Blue=50};
void main()
{
color c1 = (color)1, c2 = (color)10,
c3 = (color)40, c4 = (color)45;
{
© Keren Kalif
12
include -‫ פעולת ה‬:‫תזכורת‬
)preprocessor( ‫מעבד‬-‫ היא פקודת קדם‬include -‫ פעולת ה‬
‫ את תוכן הקובץ‬include ‫אשר שותלת בקוד במקום כל פקודת‬
‫שאותו כללנו בפקודה‬
a.h
// prototypes
void aFoo1();
int aFoo2();
main.c
#include <iostream>
#include "a.h"
void main()
}
aFoo1();
aFoo2();
{
#include <iostream>
// prototypes
void aFoo1();
int aFoo2();
void main()
}
aFoo1();
aFoo2();
{
© Keren Kalif
13
a.h
// prototypes
void aFoo1();
int aFoo2();
include ‫הבעיתיות בפקודת‬
:‫ לקובץ מסוים יותר מפעם אחת‬include ‫ יתכן ונעשה‬
b.h
#include “a.h”
// prototypes
void bGoo1();
int bGoo2();
main.cpp
#include <iostream>
#include "a.h“
#include “b.h“
void main()
}
aFoo1();
bGoo1();
{
#include <iostream>
// prototypes
void aFoo1();
int aFoo2();
// prototypes
void aFoo1();
int aFoo2();
// prototypes
Void bGoo1();
int bGoo2();
‫נקבל שגיאה של‬
redefinition
‫מאחר והקומפיילר‬
‫רואה את ההצהרה‬
‫על הפונקציות‬
b.h -‫מ‬
a.h -‫שמוגדרות ב‬
‫יותר מפעם אחת‬
a.h -‫מ‬
void main()
}
aFoo1();
bGoo1();
{
© Keren Kalif
14
‫הפתרון‪ :‬הידור מותנה‬
‫‪ ‬ראינו בעבר את הפקודה ‪ #define‬לצורך הגדרת קבוע מסוים‬
‫‪ ‬פקודה זו מוסיפה את הקבוע שהוגדר לטבלת סימולים של‬
‫התוכנית במידה וטרם הוגדר‪ .‬במידה וכבר הוגדר דורסת את‬
‫ערכו‪.‬‬
‫‪ ‬ניתן גם לכתוב פקודת ‪ define‬ללא ערך‪ ,‬רק כדי להכניס‬
‫קבוע מסוים לטבלת הסימולים‬
‫‪ ‬ניתן לבדוק האם קבוע מסוים הוגדר בטבלת הסימולים‬
‫בעזרת הפקודה ‪ #ifdef‬או אם לא הוגדר בעזרת הפקודה‬
‫‪#ifndef‬‬
‫‪ ‬במידה והתנאי מתקיים‪ ,‬הקופיילר יהדר את קטע הקוד‬
‫הבא עד אשר יתקל ב‪#endif -‬‬
‫‪15‬‬
‫‪© Keren Kalif‬‬
a.h
#ifndef __A_H
#define __A_H
// prototypes
void aFoo1();
int aFoo2();
#endif // __A_H
‫הפתרון עם הידור מותנה‬
b.h
#ifndef __B_H
#define __B_H
#include “a.h”
// prototypes
void bGoo1();
int bGoo2();
#endif // __B_H
main.cpp
#include <iostream>
#include "a.h“
#include “b.h“
void main()
}
aFoo1();
bGoo1();
{
:‫טבלת הסימולים‬
__A_H
__B_H
‫ לאחר‬main.c
preprocessor
#include <iostream>
// prototypes
void aFoo1();
int aFoo2();
// prototypes
void bGoo1();
int bGoo2();
void main()
}
aFoo1();
bGoo1();
{
main -‫כעת יש לנו ב‬
‫פעם אחת בלבד את‬
‫ההגדרות מכל קובץ‬
© Keren Kalif
16
‫בעיה נוספת ב‪include -‬‬
‫‪ ‬כאשר יש ‪ 2‬מבנים אשר כל אחד מגדיר אובייקט מטיפוס המבנה‬
‫השני‪ ,‬מתקבלת שגיאת קומפילציה שקשה להבינה‪:‬‬
‫הקומפיילר אינו מכיר את הטיפוס ‪A‬‬
‫ולכן שגיאת הקומפילציה‪...‬‬
‫‪#ifndef __B_H‬‬
‫‪#define __B_H‬‬
‫”‪#include “a.h‬‬
‫‪#ifndef __A_H‬‬
‫‪#define __A_H‬‬
‫”‪#include “b.h‬‬
‫‪struct B‬‬
‫{‬
‫;‪A a‬‬
‫;}‬
‫‪#endif // __b_H‬‬
‫‪struct A‬‬
‫{‬
‫;‪B b‬‬
‫;}‬
‫‪#endif // __A_H‬‬
‫“‪#include "a.h‬‬
‫“‪#include “b.h‬‬
‫טבלת הסימולים‪:‬‬
‫‪__A_H‬‬
‫‪__B_H‬‬
‫‪17‬‬
‫‪© Keren Kalif‬‬
‫)(‪void main‬‬
‫}‬
‫{‬
‫הפתרון‬
‫‪ ‬במקרה זה נדאג שלפחות אחד המבנים יכיל רק מצביע למבנה‬
‫השני‪ ,‬ולא אובייקט‬
‫‪ ‬כאשר יוצרים אוביקט צריך לבצע ‪ include‬לקובץ המגדיר אותו‬
‫‪ ‬כאשר יש מצביע לאובייקט לא חייבים לבצע ‪ include‬לקובץ המכיל‬
‫אותו‪ ,‬אלא להסתפק בהצהרה שמבנה זה יוגדר בהמשך‬
‫‪ ‬בקובץ ‪ cpp‬בו תהיה היצירה של האובייקט נבצע את ה‪include -‬‬
‫לקובץ בו מוגדר המבנה‬
‫‪#ifndef __A_H‬‬
‫‪#ifndef __B_H‬‬
‫‪#define __B_H‬‬
‫הצהרה שהמחלקה תוגדר בהמשך‬
‫‪18‬‬
‫‪© Keren Kalif‬‬
‫‪#define __A_H‬‬
‫”‪#include “b.h‬‬
‫;‪struct A‬‬
‫‪struct B‬‬
‫{‬
‫;‪A* a‬‬
‫;}‬
‫‪#endif // __b_H‬‬
‫‪struct A‬‬
‫{‬
‫;‪B b‬‬
‫;}‬
‫‪#endif // __A_H‬‬
‫ביחידה זו למדנו‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪19‬‬
‫העמסת פונקציות‬
‫ערכי ברירת מחדל לפונקציות‬
‫‪enum‬‬
‫בעיית ‪'include‬ים כפולים‬
‫‪© Keren Kalif‬‬