View
45
Download
4
Category
Preview:
DESCRIPTION
sınıflar
Citation preview
Sınıflar ve Nesneler
(class)
Sınıflara ve Nesnelere Giriş
� Nesneye yönelik programlama terminolojisinde, bir sınıfprogramcı tarafından tanımlanmış bir yeni tip gibidir
� Tıpkı doğal dillerdeki “sınıf” tanımı gibi:� Aynı özellikleri ve fonksiyonları paylaşan elemanlar kümesidir
� Nesneye yönelik programlamada da tanım aynıdır
� Nesneye yönelik programlama dillerinde (C++ gibi) nesneler bir kavrama ait herşeyi biraraya birleştirmeye yararlar (tarih, öğrenci gibi)� Data (durum) (e.g. öğrenci no, not ortalaması)
� Fonksiyonlar (davranış) (e.g. öğrenci kaydolur, öğrenci mezun olur)
Nesnelere Giriş� Data tiplerinden değişkenler tanımlıyoruz (int, double
gibi). Benzer şekilde, sınıflardan da nesneler tanımlarız� bir nesne bir sınıfın üyesidir
� Neden sınıflar ve nesneler? Neden nesneye dayalıprogramlama?� Programcıya detaylarla uğraşmadan raftan hazır parçalar alıp
kullanabilmesini sağlar
� Zaman ve çaba kazandırır� Nesneler de gerçek hayattaki şeylerin programda gösterimidir.
� Siz de kendi sınıflarınızı tasarlayabilir ve sonra da kullanabilirsiniz, ama önce başka programcıların tanımladığı sınıfları kullanacağız� Genellikle bir programcının yaptığı da budur
Nesneye Yönelik Programlama
� OO programlama olmadan – Takvim yazdırma programı� Bir çok yardımcı fonksiyon gerekli
� Artık yıl kontrolü
� Haftanın gününü kelimeye dönüştüren fonksiyon gerekli
� …
gün
haftanın hangi günü
ay
AyĐsmi artık yıl
yılData
Fonksiyonlar
. . .
� Bu yapı kompleks mi? • Kimisi için evet, kimisi için hayır
Nesneye Yönelik Programlama
� OO versiyonu - Takvim yazdırma programı� Tarih kavramı bir sınıf olarak geliştirilmiş
� data ve fonksiyonlar bir araya getirilmiş durumda
� Bunu sevdiniz mi? • kimisi için evet, kimisi için hayır
� OO yaklaşımı insan yapısına daha uygundur• Đnsanın kavrayışı da nesnelere dayalıdır
Data (gün, ay, yıl)
FonksiyonlarHaftanın günü
Ayın adı…
Sınıfları nasıl kullanacağız?
� Bir sınıfın davranışı üye fonksiyonları (metodları)tarafından belirlenir
� Bu üye fonksiyonları ve ne yaptıklarını bilmek gerekir� Fonksiyonun adını� Parametrelerini ve parametre tiplerini� Döndürdüğü tipi� Fonksiyonunu
� Fonksiyonun nasıl çalıştığını bilmeniz gerekmez� analoji: araba kullanırız ama yakıt enjeksiyonunun nasıl çalıştığını bilmemize gerek yoktur
Dice sınıfı
� Bilgisayar taklidi zar� Gerçek zar değil, ama aynı fonksiyona sahip
� 1 ile “zarın kenar sayısı” arasında rastgele bir sayı atıyor
� Bu sınıftan oluşturacağımız zar nesneleri istediğimiz sayıda kenara sahip olabilirler
� Kullanıcı programcı bu sınıfa şu başlık dosyasından ulaşabilir#include "dice.h“
Dice sınıfı� Küçük bir sınıf
� Örnek ile görmekte fayda var
� Durum� Kenar sayısı
� Zarın atılma sayısı
� Üye fonksiyonları
Dice(int sides); // constructor – verilen sides kenarlı bir zar oluşturur
int Roll(); // rastgele atışı döndürür
int NumSides() const; // kaç tane kenar olduğunu
int NumRolls() const; // zarın kaç kez atıldığını
Bir sınıf nerede tanımlanır?
� Sınıfın tanımı ve üye fonksiyon prototipleri ve bazı diğer tanımlamalar bir header dosyası (.h dosyası) içindedir� Fonksiyon prototipinde fonksiyon adı, döndürdüğü tipi ve
parametrelerini içerir. Fonksiyon gövdesi orada değildir.
� Üye fonksiyonların gövdeleri .cpp dosyası içindedir
� Dice örneğinde� Sınıfın tanımı dice.h dosyasındadır
� Bu yüzden roll.cpp dosyasının başına include eklenmiştir
� Sınıfın uygulaması dice.cpp dosyasındadır� VS projesinin parçası olmalıdır – birlikte link edilirler
dice.h başlık dosyası� Dice sınıfını kullanabilmek için #include "dice.h" demek gerekirclass Dice{public:Dice(int sides); // constructorint Roll(); // return the random rollint NumSides() const; // how many sides int NumRolls() const; // # times this die rolled
private:int myRollCount; // # times die rolledint mySides; // # sides on die
};
� Her Dice nesnesinin kendine has mySides ve myRollCount değişkenleri vardır� Genellikle constructor fonksiyon tarafından ilk değerleri atanırlar
Dice sınıfını kullanmak
cout << cube.NumSides() << " kenarlı zar atılıyor " << endl;
cout << cube.Roll() << endl;cout << cube.Roll() << endl;cout << cube.NumRolls()
<< " kere atıldı" << endl;üye
fonksiyonlar
Dice cube(6); //altı kenarlı zar oluşturur
Dice dodeca(12); // 12 kenarlı zar oluşturur
roll.cpp
constructor
� Nesneleri nasıl tanımlarız?
sınıf_adı nesneler_listesi_virgülle_ayrılmış;
� Eğer argumanlar istiyorsa constructor, onları da unutmayın.
� Nasıl üye fonksiyon çağırdık?
nesne_adı.fonksiyon_adı(argumanlar);
� Bir üye fonksiyon çağrıldığı nesne üzerinde işlem yapacaktır.
Nasıl?
Dice ile neler yapabiliriz, neler
yapamayız� Kenar sayısı belirtmeden Dice nesnesi yaratamayız
� Bu bir hata değil, bir tasarım kararıdır� Varolan sınıfı parametresiz bir constructor ile değiştirebilirsiniz
Dice d(2); // ok, madeni para gibi
Dice cube; // ok değil, derlenmez
� Dice nesnesi ne kadar rasgeledir – nasıl test edebiliriz?� Bir hedef toplam elde etmek için kaç kez zar atılması gerektiğini hesaplarız
� Bunu defalarca tekrarlarız bir ortalama elde etmek için
� 6 kenarlı zar kullanarak bunu 2 ve 12 arasındaki bütün değerler için tekrarlarız
� testdice.cpp
Sınıf tanımının parçaları
� Public � Üye fonksiyonlar
� Programcı sadece public bölümdekileri kullanabilir
� Constructors� Nesneleri yaratmaya yarayan özel bir üye fonksiyon (değişkenler)
� Aynı isimle birden fazla constructor olabilir, ama değişik parametrelerle
� Private� Daha ziyade sınıfın data (bilgi) kısmı burada olur
� Sınıfın kendi iç uygulaması için kullanılırlar� Örneğin. mySides – used by Roll
� Programcı göremez� Örneğin. roll.cpp , programcı mySides ı değiştiremez
Dice sınıfının kullanımı
#include "dice.h"int main(){
Dice cube(6);Dice dodeca(12);
cout << cube.Roll();
int k;for(k=0; k < 6; k++){ cout << dodeca.Roll();}return 0;
}
Nesneler oluşturuldu
0
myRollCount mySides
6
cube
0
myRollCount mySides
12
dodeca
Metodlar çağırıldı
1
myRollCount mySides
6
cube
Döngüden sonra
6
myRollCount mySides
12
dodeca
dice.cpp – 1/2
Dice::Dice(int sides)// postcondition: all private fields initialized {
myRollCount = 0;mySides = sides;
}
int Dice::NumSides() const// postcondition: return # of sides of die {
return mySides;}
Constructor
dice.cpp– 2/2
int Dice::NumRolls() const// postcondition: return # of times die has been rolled{
return myRollCount;}
int Dice::Roll()// postcondition: number of rolls updated// random 'die' roll returned {
RandGen gen; // random number generator
myRollCount= myRollCount + 1; // update # of rollsreturn gen.RandInt(1,mySides); // in range [1..mySides]
}
.cpp dosyası
� Sınıfın bütün member üye fonksiyonları bu dosyadadır� Her fonksiyonun adı, parametre listesi, ve döndürdüğü tip vardır� Bir üye fonksiyonun adında sınıfın adı da vardır
return_type sınıf_adı :: fonksiyon_adı (parametreler)
� Constructor lar bir şey döndürmezler
sınıf_adı :: sınıf_adı (parametreler)
:: operatorü fonksiyonun sınıfını belirler
� Her metot sınıfın private data bölgesine dokunabilir (cağırıldığınesnenin datasına tabii)� Böylece , her metot çağrılışında, üye fonksiyon değişik nesnelerin
private bilgisini kullanacaktırcube.NumSides() ile dodeca.NumSides()
� . operatorü üye fonksiyon cağrılacağı zaman kullanılır
RandGen Sınıfı
� Rastgele sayı üreten bir sınıf� Projenize randgen.cpp dosyasını ekleyin ve
#include "randgen.h" satırını da programınızın başına ekleyin
� Dört üye fonksiyonu var:int RandInt(int max = INT_MAX);
� [0..max) aralığında bir rastgele tamsayı üretirint RandInt(int low, int max);
� [low..max] aralığında bir rastgele tamsayı üretirdouble RandReal();
� [0..1) aralığında bir rastgele reel sayı üretirdouble RandReal(double low, double max);
� [low..max] aralığında bir rastgele reel sayı üretir
� numberguess.cpp
Aşırı yükleme (Overloading)
� RandGen sınıfında, RandInt adında iki farklıfonksiyon var� RandReal de bunun gibi aynı
� Aynı ismi birden fazla fonksiyon için kullanmaya overloading diyoruz. � Parametre tipleri ve/veya return tipleri farklıdır.
� Hem üye hem serbest fonksiyonlaraşırı yüklenebilirler.
The class Date
� The class Date is accessible to client programmers
#include "date.h"
� to get access to the class
� The compiler needs this information.
� It may also contain documentation for the programmer
� Link the implementation in date.cpp
� Add this cpp to your project
� The class Date models a calendar date:� Month, day, and year make up the state of a Date object
� Dates can be printed, compared to each other, day-of-week determined, # days in month determined, many other behaviors
� Behaviors are called methods or member functions
Constructing Date objects – see
usedate.cppDate today;Date republic(10,29,1923);Date million(1000000);Date y2k(1,1,2000);cout << "today: " << today << endl;cout << "Republic of Turkey has been founded on: "
<< republic << endl;
cout << "millionth day: " << million << endl;
OUTPUTtoday: April 12 2009
Republic of Turkey has been founded on: October 29 1923
millionth day: November 28 2738
Constructing/defining an object
� Date objects (as all other objects) are constructed when they’re first defined� Three ways to construct a Date
� default constructor, no params, initialized to today’s date
� single long int parameter, number of days from January 1, 1
� three params: month, day, year (in this order).
� Constructors for Date objects look like function calls� constructor is special member function
� Different parameter lists mean different constructors
� Once constructed, there are many ways to manipulate a Date� Increment it using ++, subtract an integer from it using -, print it using cout, …
� MonthName(), DayName(), DaysIn(), …
� See date.h for more info on date constructors and member functions
Date Member Functions
Date MidtermExam(4,6,2011);
� Construct a Date object given month, day, year
MidtermExam.DayName()
� Returns the name of the day (“Monday” or “Tuesday”, or ...)
� in this particular case, returns “Wednesday” since April 6, 2011 is a Wednesday
MidtermExam.DaysIn()
� Returns the number of days in the particular month
� in our case return 30, since April 2011 has 30 days in it
� Add, subtract, increment, decrement days from a dateDate GradesDue = MidtermExam + 2;
� GradesDue is April 8, 2011
� Let’s see usedate.cpp in full and datedemo.cpp now
Example: Father’s day (not in book)� Father’s day is the third Sunday of June
� write a function that returns the date for the father’s day of a given year which is the parameter of the function
� In main, input two years and display father’s days between those years
Date fathersday(int year)// post: returns fathers day of year{
Date d(6,1,year); // June 1
while (d.DayName() != "Sunday"){
d += 1;}
//d is now the first Sunday, 3rd is 14 days later
return d + 14;}
� See fathersday.cpp for full program
Updating a Class (not in book)
� Suppose you want to add more functionality to the date class
� need to change the header file (date.h)
� need to add implementation of new function(s) to date.cpp
� Example: a new member function to calculate and return the remaining number of days in the object’s month
� any ideas? do you think it is too difficult?
� have a look at the existing member functions and see if they are useful for you
Updating a Class (not in book)
� We can make use of DaysIn member function
� Prototype in Date class (add to the header file)int RemainingDays () const;
� Implementationint Date::RemainingDays () const{
return DaysIn() - myDay;}
� In a member function implementation private data and other member functions referred without the dot operator.� They operate on the object for which the member function is called
Updating a Class (not in book)� Example use of RemainingDays
Date today;
cout << "There are " << today.RemainingDays() <<
" days left in the current month" << endl;
� See date_modified.h, date_modified.cpp and demodatemodified.cpp
� When RemainingDays is called,� call to DaysIn is for object today
� since it is the object on which RemainingDays is called
� myDay is today’s myDay� since it is the object on which RemainingDays is called
Designing classes from scratch
� Chapter 7 (especially 7.1 and 7.2)
� a good development strategy� “iterative enhancement” approach
� READ those sections, you are responsible� we won’t cover all, because it takes too much time and becomes
boring!
� I will give a simpler class design example here� less iterative
� but similar application
Implementing Classes – Iterative
Enhancement
� It is difficult to determine what classes are needed,
how they should be implemented, which functions are required
� Experience is a good teacher, failure is also a good teacher
Good design comes from experience, experience comes from
bad design
� Design and implementation combine into a cyclical process: design, implement, re-visit design, re-implement, test, redesign, …
� Grow a working program, don’t do everything at the same time
Design and Implementation Heuristics
� A design methodology says that
“look for nouns, those are classes”, and then “look for verbs and scenarios, those are member functions”
� Not every noun is a class, not every verb is a member function� some functions will be free ones or will be implemented in main
(these are design decisions)
� Concentrate on behavior (member functions) first when designing classes, then on state (private part)� private data will show its necessity during the implementation of
the public part
Example class design
� Quiz class� simple quiz of addition questions
� Scenarios� user is asked a number of questions
� computer asks random questions
� user enters his/her answer� correct / not correct
� feedback and correct answer are displayed
� correct answers are counted
� There may be two classes� question
� quiz
� but I will have one class which is for question and implement quiz in main� Be careful! This example is similar but different than the one in
book (Sections 7.1 and 7.2)
Question class
� Question behaviors (verbs). A question is� created
� asked
� answered
� checked
� These are candidate member functions� more? less? we will see
� A question is simply two random integers (to keep it simple say between 1 and 100) to be added� those numbers are definitely in class private data
� what else?� we will see
Question class� simplemathquest.h (first draft)
class Question
{
public:
Question(); // create a random question
void Ask() const; // ask the question to user
int GetAnswer() const; //input and return user answer
bool IsCorrect(int answer) const; //check if correct
private:
int myNum1; // numbers used in question
int myNum2;
};
Quiz program (main - simplequiz.cpp) – Draft 1
int qNum = PromptRange("how many questions: ",1,5);int k, ans, score =0;
for(k=0; k < qNum; k++){
Question q;q.Ask();ans = q.GetAnswer();if (q.IsCorrect(ans)){
cout << ans << " correct answer" << endl << endl;score++;
}else{
cout << "Sorry, not correct. Correct answer was " << ???????? << endl << endl;
}}cout << "Score is " << score << " out of " << qNum
<< " = " << double(score)/qNum * 100 << "%" << endl;
� Something missing: a function to return the correct result
Question class
� simplemathquest.h (second draft)
class Question
{
public:
Question(); // create a random question
void Ask() const; // ask the question to user
int GetAnswer() const; //input and return user answer
bool IsCorrect(int answer) const; //check if correct
int CorrectAnswer() const; //return the correct answer
private:
int myNum1; // numbers used in question
int myNum2;
};
Quiz program (simplequiz.cpp) – Draft 2
int qNum = PromptRange("how many questions: ",1,5);
int k, ans, score =0;
for(k=0; k < qNum; k++)
{
Question q;
q.Ask();
ans = q.GetAnswer();
if (q.IsCorrect(ans))
{ cout << ans << " correct answer" << endl << endl;
score++;
}
else
{ cout << "Sorry, not correct. Correct answer was " << q.CorrectAnswer() << endl << endl;
}
}
cout << "Score is " << score << " out of " << qNum
<< " = " << double(score)/qNum * 100 << "%" << endl;
Question class implementation� simplemathquest.cpp (draft 1)
void Question::Ask() const
{
cout << myNum1 << " + " << myNum2 << " = ";
}
Question::Question()
{
RandGen gen;
myNum1 = gen.RandInt(1,100);
myNum2 = gen.RandInt(1,100);
}
constructor
int Question::GetAnswer() const
{
int ans;
cin >> ans;
return ans;
}
Ooops! We did not access or modify the object’s state. It is better not to have this function
as a member function
Question class implementation
� simplemathquest.cpp (draft 1) - continued
� Problem: Where is the correct answer stored?� a new private data field would be good
bool Question::IsCorrect(int answer) const
{
return ?????? == answer;
}
int Question::CorrectAnswer() const
{
return ??????;
}
Question class� simplemathquest.h (final)
class Question
{
public:
Question(); // create a random question
void Ask() const; // ask the question to user
bool IsCorrect(int answer) const; //check if correct
int CorrectAnswer() const; //return the correct answer
private:
int myNum1; // numbers used in question
int myNum2;
int myAnswer; // store the answer
};
int GetAnswer() const; //input and return user answer
Question class implementation� simplemathquest.cpp (final)Question::Question()
{
RandGen gen;
myNum1 = gen.RandInt(1,100);
myNum2 = gen.RandInt(1,100);
myAnswer = myNum1 + myNum2;
}
void Question::Ask() const
{
cout << myNum1 << " + " << myNum2 << " = ";
}
int Question::GetAnswer() const{int ans;
cin >> ans;return ans;}
Question class implementation
� simplemathquest.cpp (final) - continued
bool Question::IsCorrect(int answer) const
{
return myAnswer == answer;
}
int Question::CorrectAnswer() const
{
return myAnswer;
}
Quiz program (simplequiz.cpp) – Final
int qNum = PromptRange("how many questions: ",1,5);int k, ans, score =0;
for(k=0; k < qNum; k++){
Question q;q.Ask();cin >> ans;if (q.IsCorrect(ans)){
cout << ans << " correct answer" << endl << endl;score++;
}else{ cout << "Sorry, not correct. Correct answer was " <<
q.CorrectAnswer() << endl << endl;}
}cout << "Score is " << score << " out of " << qNum
<< " = " << double(score)/qNum * 100 << "%" << endl;
Thinking further� What about a generic question class
� not only addition, but also other arithmetic operations� may need another private data member for the operation that is
also useful to display the sign of operation in Ask
� may need parameter in the constructor (for question type)
� will do this week in recitations
� What about questions for which answers are strings?� maybe our generic question class should have string type answers to serve not
only to arithmetic questions but any type of questions
� see Sections 7.1 and 7.2
string as a class� string is a class
� string variables are objects, they’re instances of the class
� A class is a collection of members that have common attributes � strings share some properties, but have different values
� A string is a sequence of characters� first char is at position 0
� first index is 0
� last valid index (position of the last character): string’s length -1
� Constructors� without initialization
string mystr, s;
� with initializationstring s = "Hello World";
string otherstring = s; or string otherstring(s);
� You may use functions and operators that return strings in initializationstring s = "Hello" + "World"; //concatenation operator
string member functions
� The function length() returns the number of characters
string s = "hello";int len = s.length(); // value of len is 5
s = ""; // s is null stringlen = s.length(); // value of len is 0
� Member functions are applied to objects using dot notation� Cannot use length() without an object to apply it to
� Not valid int x = length(s);
� Not valid int x = string.length();
� Valid? double y = sqrt(s.length());
string member functions
int length()
// postcondition: returns the number of characters
string substr(int pos, int len)
// precondition: 0 <= pos, and pos < length of the string object
// postcondition: returns substring of len characters beginning at position
// pos. Returns as many characters as possible if len is too large, but
// causes error if pos is out of range (>= length of the string object)
int find(string s)
// postcondition: returns first position/index at which substring s begins in
// string object– returns string::npos if s does not occur
Extracting substrings
� A substring is part of a string, substrings can be extracted from a string using member function substr
string s = "theater";int len = s.length(); // value of len is 7string t = s.substr(0,3); // t is "the", s is “theater”t = s.substr(1,4); // t is now “heat”s = s.substr(3,3); // s is “ate” t is still “heat”
s = “cinema”;t = s.substr(4,8); // t is “ma”t = s.substr(8,2); // run-time error
� See strdemo.cpp which is a sample program that uses length and substr functions
0
t h
1 2
a
3
e t e r
4 5 6
0
c i
1 2
e
3
n m a
4 5
Finding substrings within strings: find and rfind
� String member function find looks for an occurrence of one string (which is a parameter) in another (which is the object string), returns position of the start of the first occurrence� If no occurrence, then string::npos is returned
� largest unsigned integer (4,294,967,295)
string s = "I am the eggman, he is too";int k = s.find("I"); // k is 0k = s.find("he"); // k is 6k = s.find("egg"); // k is 9k = s.find("a"); // k is 2cout << s.find("cat"); // output is 4294967295
k = s.find("cat"); // k is –1 since it is signed, // we should use unsigned int
� rfind is same as find, but searches backwards, returns the last occurrencek = s.rfind("he"); // k is 17k = s.rfind("egg"); // k is 9
� See strfind.cpp which is a sample program on find function
find and rfind with 2 parameters
� There is another version of find and rfind that takes two parameters � First parameter is still a string (the search string)� Second parameter is an integer (an index value) � In this version, searching starts from the character for which the index is the second parameter of find or rfind
� Useful when you need to search a string not from the endpoint, but from somewhere in the middle
string s = "I am the eggman, he is too";int k;k = s.find("a"); // k is 2
k = s.find("a",5); // k is 13
k = s.rfind("he"); // k is 17k = s.rfind("he", 15); // k is 6
More on strings
� You can append one string to the end of another� using operator +
string s = "cs201";
s = s + " is easy"; // s is now "cs201 is easy"
� You can change or extract one character of a string using atmember function� parameter of at must be between 0 and string’s length - 1, otherwise a
run-time error occurs
string s = "Hello World";
s.at(4) = '!'; // s is now "Hell! World"
cout << s.at(1); // displays e on screen
s.at(20) = 'a'; // run-time error
Example (See stringremove.cpp)� Write a function that takes two string parameters (say s1 and s2). Function removes first occurrence of s2 in s1 and returns the resulting string.� In the main program, test the function by removing some input strings from “Today is Monday”
� See program in next slide
Example (See stringremove.cpp)
string remove(string s1, string s2)
// post: removes first occurrence of s2 from s1 and returns the
// resulting string.
// Returns s1 if s2 does not occur any.
{
unsigned int location;
string temp = s1;
location = s1.find(s2);
if (location != string::npos)
{
temp = s1.substr(0, location) + s1.substr(location+s2.length(), s1.length());
}
return temp;
}
Example: Print a string backwards Example: Print a string backwards
((revstring.cpprevstring.cpp))
� Determine the index of the last character of the string,and then access each character backwards� How many times should the loop iterate ?
string s; int k;cout << "enter string: ";cin >> s;cout << s << " reversed is ";
k = s.length() - 1; // index of last character in swhile (k >= 0){
cout << s.substr(k,1);k -= 1;
}cout << endl;
� What could we use instead of s.substr(k,1) ?s.at(k)
Reverse String as a function
� First step, what is the prototype?
string revstring(string s)// pre: s = c0c1c2…cn-1// post: return cn-1…c2c1c0
� Second step, how do we build a new string?� Start with an empty string, ""� Add one character at each iteration using concatenation, +
rev = rev + s.substr(k,1);
� Use revstring to determine if a string is a palindrome
See palindrome.cpp for full program
string revstring(string s)
// post: returns reverse of s, that is "stab" for "bats“
{
int k = s.length() – 1;
string rev = ""; // start with empty string
while (k >= 0)
{
rev = rev + s.substr(k,1);
k -= 1;
}
return rev;
}
bool IsPalindrome(string word)
// post: returns true if and only word is a palindrome
{
return (word == revstring(word));
}
Recommended