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