? ? ? ? 在C++中,關(guān)于面向?qū)ο蟪绦蛟O(shè)計已經(jīng)講了很大篇幅,也例舉很多案例,此篇將通過一些習(xí)題來進一步了解對象、靜態(tài)成員、指針、引用、友元、類模板等等相關(guān)知識。
一、習(xí)題一(構(gòu)造函數(shù)默認(rèn)參數(shù))
? ? ? ? 示例代碼:
#include <iostream>
using namespace std;
class Date{
public:
Date(int, int, int);
Date(int, int);
Date(int);
Date();
void display();
private:
int month;
int day;
int year;
};
Date::Date(int m, int d, int y): month(m), day(d), year(y) {}
Date::Date(int m, int d): month(m), day(d){
year = 2005;
}
Date::Date(int m): month(m){
day = 1;
}
Date::Date(){
month = 1;
day = 1;
year = 2005;
}
void Date::display(){
cout <<month <<"/" <<day <<"/" <<year <<endl;
}
int main(){
Date d1(10, 13, 2005);
Date d2(12, 30);
Date d3(10);
Date d4;
d1.display();
d2.display();
d3.display();
d4.display();
return 0;
}
? ? ? ? 如上代碼,運行后結(jié)果如下圖:
1.1 提問
????????現(xiàn)在將上述代碼中,第5行的構(gòu)造函數(shù)中添加默認(rèn)參數(shù),即:
Date(int=1, int=1, int=2005);
? ? ? ? 分析此程序是否有問題,并分析出錯誤信息,修改程序后使之能通過編譯,得到上圖一樣結(jié)果。
????????解答:
? ? ? ? 關(guān)于構(gòu)造函數(shù)前面也講過,地址:C++面向?qū)ο蟪绦蛟O(shè)計 - 構(gòu)造函數(shù)-CSDN博客,在該篇的“六、構(gòu)造函數(shù)添加默認(rèn)參數(shù)”中作了簡單闡述。當(dāng)時時建議大家在寫構(gòu)造函數(shù)時,盡量不要使用默認(rèn)參數(shù),因為一般程序員對此不好把控,編譯時會出現(xiàn)錯誤【call of overloaded 'function_name' is ambiguous】。在構(gòu)造函數(shù)形參中添加默認(rèn)參數(shù),通常編譯器在嘗試解析構(gòu)造函數(shù)時發(fā)現(xiàn)了多個可能的匹配項,它無法確定應(yīng)該使用哪一個,因為所有這此匹配項在某種程序上都是可行的。
? ? ? ? 將構(gòu)造函數(shù)中添加默認(rèn)參數(shù)代碼(錯誤代碼)如下:
#include <iostream>
using namespace std;
class Date{
public:
Date(int=1, int=1, int=2005);
Date(int, int);
Date(int);
Date();
void display();
private:
int month;
int day;
int year;
};
Date::Date(int m, int d, int y): month(m), day(d), year(y) {}
Date::Date(int m, int d): month(m), day(d){
year = 2005;
}
Date::Date(int m): month(m){
day = 1;
}
Date::Date(){
month = 1;
day = 1;
year = 2005;
}
void Date::display(){
cout <<month <<"/" <<day <<"/" <<year <<endl;
}
int main(){
Date d1(10, 13, 2005);
Date d2(12, 30);
Date d3(10);
Date d4;
d1.display();
d2.display();
d3.display();
d4.display();
return 0;
}
? ? ? ? 此時運行時,編譯器會報錯【[Error] call of overloaded 'Date(int, int)' is ambiguous】- 調(diào)用重載的'Date(int, int)'是不明確的。
? ? ? ? 上述代碼中,在定義d2,d3,d4時,其實構(gòu)造函數(shù)Date(int=1, int=1, int=2005)都是可行的,將會一直匹配第一個構(gòu)造函數(shù),后面定義的Date(int, int)、Date(int)、Date()將不會被匹配到。所以此題想要解決此問題,將后面三個構(gòu)造函數(shù)刪除即可,代碼(正確代碼)如下:
#include <iostream>
using namespace std;
class Date{
public:
Date(int=1, int=1, int=2005);
void display();
private:
int month;
int day;
int year;
};
Date::Date(int m, int d, int y): month(m), day(d), year(y) {}
void Date::display(){
cout <<month <<"/" <<day <<"/" <<year <<endl;
}
int main(){
Date d1(10, 13, 2005);
Date d2(12, 30);
Date d3(10);
Date d4;
d1.display();
d2.display();
d3.display();
d4.display();
return 0;
}
? ? ? ? 其運行結(jié)果和前面也是一樣的。
二、習(xí)題二(指針)
2.1?提問一
????????建立一個對象數(shù)組,內(nèi)放5個學(xué)生的數(shù)據(jù)(學(xué)號、成績),用指針指向數(shù)組首元素,輸出第1,3,5個學(xué)生的數(shù)據(jù)。
????????解答:
????????在前面篇幅講到指針(C++面向?qū)ο蟪绦蛟O(shè)計 - 對象指針和this指針-CSDN博客),在“三、對象數(shù)組的指針”中講到把數(shù)組賦值給指針變量是指向數(shù)組中第一個元素,所以此題代碼如下:
#include <iostream>
using namespace std;
class Student{
private:
int num; //學(xué)號
int score; //成績
public:
Student(int n, int s): num(n), score(s){}
void display(){
cout <<"num:" <<num <<", score:" <<score <<endl;
};
};
int main(){
Student sArr[5] = {
Student(1001, 87),
Student(1002, 98),
Student(1003, 89),
Student(1004, 92),
Student(1005, 81)
};
Student *p = sArr;
//顯示第1個
p->display();
//顯示第3個
(p+2)->display();
//顯示第5個
(p+4)->display();
return 0;
}
? ? ? ? 通過指針的移位,輸出指針對應(yīng)的Student對象數(shù)據(jù),結(jié)果如下圖:
2.2?提問二
????????在學(xué)生Student對象中設(shè)立一個函數(shù)max,用指向?qū)ο蟮闹羔樧骱瘮?shù)參數(shù),在max函數(shù)中找到5個學(xué)生中成績最高者,并輸出其學(xué)號。
????????解答:
????????此題讓我們首先想到的則是靜態(tài)成員,這里就先按題目中的方法,在對象中定義一個靜態(tài)max函數(shù)用來找到5名學(xué)生中成績最高者。代碼如下:
#include <iostream>
using namespace std;
class Student{
private:
int num; //學(xué)號
int score; //成績
public:
Student(int n, int s): num(n), score(s){}
void display(){
cout <<"num:" <<num <<", score:" <<score <<endl;
}
get_num(){ return this->num; }
get_score(){ return this->score; }
// 聲明獲取成績最高的學(xué)生
static Student max(Student*, int);
};
// 定義靜態(tài)成員函數(shù)max
Student Student::max(Student* stuArr, int size){
Student maxStu = (*stuArr); //默認(rèn)第一個為第大值
for(int i = 0; i < size; i++){
if(stuArr[i].get_score() > maxStu.get_score()){
maxStu = stuArr[i];
}
}
return maxStu;
};
int main(){
Student sArr[5] = {
Student(1001, 87),
Student(1002, 98),
Student(1003, 89),
Student(1004, 92),
Student(1005, 81)
};
// 顯示成績最高者
Student h = Student::max(sArr, 5);
h.display();
return 0;
}
? ? ? ? 運行結(jié)果如下圖:
2.3 提問三
???????? 對于“提問二”,也可以脫題使用靜態(tài)數(shù)據(jù)成員來完成,定義HighNum和HighScore來存儲最高者的學(xué)號和成績,并在構(gòu)造函數(shù)中判斷初始值誰的成績最高,其結(jié)果也是一樣的。代碼如下:
#include <iostream>
using namespace std;
class Student{
private:
int num; //學(xué)號
int score; //成績
static int HighNum; //最高者編號
static int HighScore; //最高者成績
public:
Student(int n, int s): num(n), score(s){
// 判斷最大值
if(s>HighScore){
HighScore = s;
HighNum = n;
}
}
void display(){
cout <<"num:" <<num <<", score:" <<score <<endl;
}
// 顯示最大值
static void max(){
cout <<"num:" <<HighNum <<", score:" <<HighScore <<endl;
}
};
// 初始化靜態(tài)數(shù)據(jù)成員
int Student::HighNum = 0;
int Student::HighScore = 0;
int main(){
Student sArr[5] = {
Student(1001, 87),
Student(1002, 98),
Student(1003, 89),
Student(1004, 92),
Student(1005, 81)
};
// 顯示成績最高者
Student::max();
return 0;
}
????????解答:
????????可能有些人在想,這里Student對象中數(shù)據(jù)成員較少,但如果遇到數(shù)據(jù)成員較多的,此時輸出最高者的信息不是要定義很多對應(yīng)最高者的數(shù)據(jù)成員,代碼顯示會比較臃腫。所以獲取最高者,并能輸出最高者中所有數(shù)據(jù)成員信息(不受數(shù)據(jù)成員限制),明顯是記錄Student對象最高效的。在這保留最高分這個數(shù)據(jù)成員,將第另個靜態(tài)數(shù)據(jù)成員改為對應(yīng)的Student對象。代碼如下:
#include <iostream>
using namespace std;
class Student{
private:
int num; //學(xué)號
int score; //成績
static int HighScore; //最高者成績
static Student stu; //最高者
public:
Student(int n, int s): num(n), score(s){
// 判斷最大值
if(s>HighScore){
HighScore = s;
stu = (*this);
}
}
void display(){
cout <<"num:" <<num <<", score:" <<score <<endl;
}
// 成績最高者
static Student max(){
return stu;
}
};
// 初始化靜態(tài)數(shù)據(jù)成員
int Student::HighScore = 0;
Student Student::stu = Student(0, 0);
int main(){
Student sArr[5] = {
Student(1001, 87),
Student(1002, 98),
Student(1003, 89),
Student(1004, 92),
Student(1005, 81)
};
// 顯示成績最高者
Student s = Student::max();
s.display();
return 0;
}
? ? ? ? 此時運行后的結(jié)果依然是一樣的。
三、習(xí)題三(常對象、常指針、引用)
? ? ? ? 示例代碼:
#include <iostream>
using namespace std;
class Student{
public:
Student(int n, float s): num(n), score(s){}
void change(int n, float s){
num = n;
score = s;
}
void display(){
cout <<num <<" " <<score <<endl;
}
private:
int num;
float score;
};
int main(){
Student stu(101, 78.5);
stu.display();
stu.change(101, 80.5);
stu.display();
return 0;
}
? ? ? ? 運行結(jié)果如下:
3.1 提問一
? ? ? ? 將main函數(shù)第2行修改為:
const Student stu(101, 78.5);
? ? ? ? 解答:如上述方法,主要會出現(xiàn)以下兩個錯誤:
- 如果嘗試通過const對象來調(diào)用非const成員函數(shù),編譯器會報錯,因非const成員函數(shù)需要一個指向非const對象的this指針,而const對象只能提供一個指向const對象的this指針。所以當(dāng)執(zhí)行到stu.display()時會報錯【[Error] passing 'const Student' as 'this' argument discards qualifiers [-fpermissive]】- 將'const Student'作為'this'參數(shù)傳遞時會放棄限定符。解決方法則是將change成員函數(shù)和display成員函數(shù)都定義為常成員函數(shù)。
- 一旦創(chuàng)建一個const對象,它的任何成員都不能被修改。然而試圖使用change()函數(shù)來修改對象的num和score成員,是不允許的。但是C++中也給出解決方案,可以在數(shù)據(jù)成員前面添加mutable。否則編譯器會報錯【[Error] assignment of member 'Student::num' in read-only object】- 在只讀對象中分配成員'Student::num'。
? ? ? ? 按上述問題進行修改后,程序則可以正常編譯并運行,代碼如下:
#include <iostream>
using namespace std;
class Student{
public:
Student(int n, float s): num(n), score(s){}
void change(int n, float s) const {
num = n;
score = s;
}
void display() const {
cout <<num <<" " <<score <<endl;
};
private:
mutable int num;
mutable float score;
};
int main(){
const Student stu(101, 78.5);
stu.display();
stu.change(101, 80.5);
stu.display();
return 0;
}
3.2 提問二
? ? ? ? 將main函數(shù)改為以下內(nèi)容,其他問題扔為示例中代碼:
int main(){
Student stu(101, 78.5);
const Student *p = &stu;
p->display();
p->change(101, 80.5);
p->display();
return 0;
}
????????解答:這題是先定義一個Student類型的對象,并使用一個指向const Student的指針來指向這個對象,一般稱為常對象的指針變量。即然是常對象,則與“提問一”中是一樣的問題,指針變量p也只能調(diào)用常成員函數(shù),以及數(shù)據(jù)成員無法修改等問題。所以按“提問一”中代碼修改即可,代碼如下:
#include <iostream>
using namespace std;
class Student{
public:
Student(int n, float s): num(n), score(s){}
void change(int n, float s) const {
num = n;
score = s;
}
void display() const {
cout <<num <<" " <<score <<endl;
}
private:
mutable int num;
mutable float score;
};
int main(){
Student stu(101, 78.5);
const Student *p = &stu;
p->display();
p->change(101, 80.5);
p->display();
return 0;
}
3.3 提問三
? ? ? ? 把“提問二”中的第3行改為以下內(nèi)容,其他問題扔為示例中代碼:
Student * const p = &stu;
? ? ? ? 解答:這里是創(chuàng)建了一個指向Student對象的常量指針,這個const修飾的是指針p本身,而不是所指向的Student對象。這意味著常指針這初始化指向&stu后,不能重新賦值指針,但可以通過p修改它所指向的Student對象的內(nèi)容。所以不會影響示例中Student對象,代碼如下:
#include <iostream>
using namespace std;
class Student{
public:
Student(int n, float s): num(n), score(s){}
void change(int n, float s) {
num = n;
score = s;
}
void display() {
cout <<num <<" " <<score <<endl;
}
private:
int num;
float score;
};
int main(){
Student stu(101, 78.5);
Student * const p = &stu;
p->display();
p->change(101, 80.5);
p->display();
return 0;
}
3.4 提問四
? ? ? ? 在程序中增加一個fun函數(shù),在main函數(shù)中調(diào)用fun函數(shù),在fun函數(shù)中調(diào)用change和display函數(shù),在fun函數(shù)中使用對象引用(Student &)作為形參。
? ? ? ? 解答:一個變量的引用其實就是變量的別名,變量名和引用名指向是同一段內(nèi)存單元,所以在fun函數(shù)中無修改,直接通過引用的別名調(diào)用即可。代碼如下:
#include <iostream>
using namespace std;
class Student{
public:
Student(int n, float s): num(n), score(s){}
void change(int n, float s) {
num = n;
score = s;
}
void display() {
cout <<num <<" " <<score <<endl;
}
private:
int num;
float score;
};
// 新增的fun函數(shù)
void fun(Student &s){
s.display();
s.change(101, 80.5);
s.display();
}
int main(){
Student stu(101, 78.5);
fun(stu);
return 0;
}
四、習(xí)題四(友元)
? ? ? ? 在上篇(C++面向?qū)ο蟪绦蛟O(shè)計 - 靜態(tài)成員、友元-CSDN博客)中已經(jīng)列舉了友元的相關(guān)內(nèi)容,需要了解的朋友可以前去查看。
? ? ? ? 示例代碼:
#include <iostream>
using namespace std;
class Date;
class Time{
public:
Time(int, int, int);
void display(Date &);
private:
int hour;
int minute;
int second;
};
class Date{
public:
Date(int, int, int);
// 聲明Time類中的display函數(shù)為本類的友元成員函數(shù)
friend void Time::display(Date &);
private:
int year;
int month;
int day;
};
Time::Time(int h, int m, int s): hour(h), minute(m), second(s){}
void Time::display(Date &d){
cout <<d.year <<"/" <<d.month <<"/" <<d.day <<" " <<hour <<":" <<minute <<":" <<second <<endl;
}
Date::Date(int y, int m, int d): year(y), month(m), day(d){}
int main(){
Time t1(10, 13, 56);
Date d1(2024, 12, 25);
t1.display(d1);
return 0;
}
? ? ? ? 運行輸出結(jié)果如下:
4.1 提問一
? ? ? ? 將示例中的display函數(shù)不放在Time類中,而作為類外的普通函數(shù),然后分別在Time和Date類中將display聲明為友元函數(shù)。在主函數(shù)中調(diào)用display函數(shù),display函數(shù)分別引用Time和Date兩個類的對象的私有數(shù)據(jù),輸出年、月、日和時、分、秒。
? ? ? ? 解答:此題是將display定義為友元函數(shù),比較簡單,將display在Time和Date類中聲明為友元函數(shù)即可。另外對構(gòu)造函數(shù)也作了些調(diào)整,將在類體外定義改為類體內(nèi)定義構(gòu)造函數(shù),并初始化數(shù)據(jù)成員。代碼如下:
#include <iostream>
using namespace std;
class Date;
class Time{
public:
Time(int h, int m, int s): hour(h), minute(m), second(s){}
// 聲明display為友函數(shù)
friend void display(Time &, Date &);
private:
int hour;
int minute;
int second;
};
class Date{
public:
Date(int y, int m, int d): year(y), month(m), day(d){}
// 聲明display為友函數(shù)
friend void display(Time &, Date &);
private:
int year;
int month;
int day;
};
// 定義display函數(shù) - 顯示時間
void display(Time &t, Date &d){
cout <<d.year <<'/' <<d.month <<'/' <<d.day <<' ' <<t.hour <<':' <<t.minute <<':' <<t.second <<endl;
}
int main(){
Time t(23, 59, 59);
Date d(2024, 4, 14);
// 顯示時間
display(t, d);
return 0;
}
4.2 提問二
? ? ? ? 將示例中Date類聲明為Time類的友元類,通過Date類中的display函數(shù)引用Time類對象的私有數(shù)據(jù),輸出年、月、日和時、分、秒。
? ? ? ? 解答:此題是將示例中friend友元聲明函數(shù)到Time中,將display函數(shù)變成Date的成員函數(shù)即可;并且注意修改Date類和Time定義順序,第一行聲明的class Date需要修改為class Time。代碼如下:
#include <iostream>
using namespace std;
class Time;
class Date{
public:
Date(int y, int m, int d): year(y), month(m), day(d){}
void display(Time &);
private:
int year;
int month;
int day;
};
class Time{
public:
Time(int h, int m, int s): hour(h), minute(m), second(s){}
// 聲明Date類中display為Time類的友函數(shù)
friend void Date::display(Time &);
private:
int hour;
int minute;
int second;
};
void Date::display(Time &t){
cout <<year <<'/' <<month <<'/' <<day <<' ' <<t.hour <<':' <<t.minute <<':' <<t.second <<endl;
}
int main(){
Time t(23, 59, 59);
Date d(2024, 4, 14);
// 顯示時間
d.display(t);
return 0;
}
五、習(xí)題五(類模板)
? ? ? ? 示例代碼:
#include <iostream>
using namespace std;
template<class numtype>
class Compare{
public:
Compare(numtype a, numtype b){
x = a;
y = b;
}
// 獲取最大值
numtype max(){
return x>y?x:y;
}
// 獲取最小值
numtype min(){
return x>y?y:x;
}
private:
numtype x, y;
};
int main(){
Compare<int> cp1(3, 7);
cout <<cp1.max() <<" is the Maximum of two integer numbers." <<endl;
cout <<cp1.min() <<" is the Minimum of two integer numbers." <<endl <<endl;
Compare<float> cp2(45.78f, 93.6f);
cout <<cp2.max() <<" is the Maximum of two float numbers." <<endl;
cout <<cp2.min() <<" is the Minimum of two float numbers." <<endl <<endl;
Compare<char> cp3('a', 'A');
cout <<cp3.max() <<" is the Maximum of two char numbers." <<endl;
cout <<cp3.min() <<" is the Minimum of two char numbers." <<endl <<endl;
return 0;
}
? ? ? ? 運行結(jié)果如下圖:
5.1 提問
? ? ? ? 將示例中程序改寫為在類模板外定義各成員函數(shù)。
? ? ? ? 解答:如果成員函數(shù)是在類模板外定義的,則不能用一般定義類成員函數(shù)的形式。需要注意以下幾點:
- 在類模板內(nèi)部,構(gòu)造函數(shù)只是被聲明了,沒有定義體。
- 在類模板外部,構(gòu)造函數(shù)的定義使用了template<class numtype>來指明它是一個模板類的成員函數(shù)。
- 構(gòu)造函數(shù)的定義后跟著Compare<numtype>::Compare(numtype a, numtype b),這表示我們正在定義Compare模板類的構(gòu)造函數(shù)。
? ? ? ? 在類模板外部定義成員函數(shù),代碼如下:
#include <iostream>
using namespace std;
template<class numtype>
class Compare{
public:
Compare(numtype, numtype); //聲明構(gòu)造函數(shù)
numtype max(); //聲明成員函數(shù)max
numtype min(); //聲明成員函數(shù)min
private:
numtype x, y;
};
// 在類模板外定義構(gòu)造函數(shù)
template<class numtype>
Compare<numtype>::Compare(numtype a, numtype b): x(a), y(b){}
// 在類模板外定義成員函數(shù)max、
template<class numtype>
numtype Compare<numtype>::max(){
return x>y?x:y;
}
// 在類模板外定義成員函數(shù)min
template<class numtype>
numtype Compare<numtype>::min(){
return x>y?y:x;
}
int main(){
Compare<int> cp1(3, 7);
cout <<cp1.max() <<" is the Maximum of two integer numbers." <<endl;
cout <<cp1.min() <<" is the Minimum of two integer numbers." <<endl <<endl;
Compare<float> cp2(45.78f, 93.6f);
cout <<cp2.max() <<" is the Maximum of two float numbers." <<endl;
cout <<cp2.min() <<" is the Minimum of two float numbers." <<endl <<endl;
Compare<char> cp3('a', 'A');
cout <<cp3.max() <<" is the Maximum of two char numbers." <<endl;
cout <<cp3.min() <<" is the Minimum of two char numbers." <<endl <<endl;
return 0;
}
? ? ? ?如在在類模板體外定義成員函數(shù),第1行是聲明類模板,第2行第一個numtype是虛擬類型名,后面Compare<numtype>是一個整體,是帶參的類;表示所定義的max函數(shù)是在類Compare<numtype>的作用域內(nèi)的;在定義對象時,用戶要指定實際的類型(如int),進行編譯時就會將類模板中的虛擬類型名numtype全部用實際的類型代替,這樣Compare<numtype>就相當(dāng)于一個實際的類。文章來源:http://www.zghlxwxcb.cn/news/detail-853289.html
????????類模板聲明和使用在上篇(C++面向?qū)ο蟪绦蛟O(shè)計 - 類模板-CSDN博客)中已講解,在“四、歸納”中也歸納幾種形式。文章來源地址http://www.zghlxwxcb.cn/news/detail-853289.html
到了這里,關(guān)于C++面向?qū)ο蟪绦蛟O(shè)計 - 類和對象進一步討論的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!