(下)部分內容主要關注封裝、繼承和多態的操作。
傳送門:
第一階段(下):類與對象、封裝、繼承和多態
4.類及其使用
類的學習需要掌握的內容如下:
用一個例子來解釋:
新建lei.h頭文件和lei.cpp源文件
代碼如下:
//lei.h
class Date {
public:
void SetDate(int a, int b, int c);
void ShowDate();
private:
int year;
int month;
int day;
};
//lei.cpp
#include "stdafx.h"
#include "lei.h"
#include <iostream>
using namespace std;
void Date::SetDate(int a, int b, int c)
{
year = a;
month = b;
day = c;
}
void Date::ShowDate()
{
cout << year << "年" << month << "月" << day << "日" << endl;
}
在main函數中
int main()
{
Date test;
test.SetDate(2018, 6, 2);
test.ShowDate();
return 0;
}
結果如下:
這裏特別注意private和protect兩種訪問形式的區別,一般只有在派生類時纔有所體現,派生自基類(如例中的Date)的類訪問基類時,可以訪問protect成員,而不能訪問private成員。
構造函數:一般用於初始化成員變量的值,如本例中可以將SetDate(int a, int b, int c)函數作爲構造函數,在創建一個實例後,自動進行初始化賦值。
Date::Date(int a, int b, int c)
{
year = a;
month = b;
day = c;
}
Date::~Date()
{
cout << "Destroy" << endl;
}
void Date::ShowDate()
{
cout << year << "年" << month << "月" << day << "日" << endl;
}
int main()
{
Date test(2018,6,1); //實例化時直接初始化
test.ShowDate();
return 0;
}
5.封裝
封裝的定義以及需要掌握的內容如下:
5.1 this指針
只能在類的成員函數中進行調用,如下所示
void Date::SetDate(int year, int month, int day)
{
this->year = year; //通過this指針訪問類中的私有變量year,並與形參中的year進行區分
this->month = month;
this->day = day;
}
5.2 友元函數friend
可以訪問與其有friend關係中類的私有成員,實現類間的數據共享,定義如下。
5.2.1 全局友元函數(類與普通函數之間的數據共享)
.h文件:
class Date {
public:
void SetDate(int year, int month, int day);
void ShowDate();
friend void Call(Date &); //全局友元函數
private:
int year;
int month;
int day;
};
.cpp文件
#include "stdafx.h"
#include "lei.h"
#include <iostream>
using namespace std;
void Date::SetDate(int year, int month, int day)
{
this->year = year;
this->month = month;
this->day = day;
}
void Call(Date &t)
{
cout<<"Call:"<<t.year << "年" << t.month << "月" << t.day << "日" << endl; 、、可以訪問Date類的數據
}
main函數中
int main()
{
Date test;
test.SetDate(2018,6,2);
Call(test); //輸出2018年6月2日
return 0;
}
5.2.2 友元成員函數(不同類之間的數據共享)
.h文件:
class Time; //先聲明
class Date {
public:
//Date();
void SetDate(int year, int month, int day);
//~Date();
//void ShowDate();
void Call(Time &); //聲明成員函數
private:
int year;
int month;
int day;
};
class Time {
public:
Time(int = 2018, int = 1, int = 1);
friend void Date::Call(Time&); //將成員函數Call作爲本類的友元函數
private:
int y;
int m;
int d;
};
.cpp文件
#include "stdafx.h"
#include "lei.h"
#include <iostream>
using namespace std;
void Date::SetDate(int year, int month, int day)
{
this->year = year;
this->month = month;
this->day = day;
}
void Date::Call(Time &d)
{
cout<<"Date中的成員變量:"<<year << "年" << month << "月" << day << "日" << endl;
cout << "Time中的成員變量:" << d.y << "年" << d.m << "月" << d.d << "日" << endl;
}
Time::Time(int y, int m, int d)
{
this->y = y;
this->m = m;
this->d = d;
}
main函數中
int main()
{
Time t;
Date d;
d.SetDate(2018,6,2);
d.Call(t);
return 0;
}
輸出結果如下,可以看到Call(Time &d)函數可以訪問Time中的private變量
6.繼承與派生
如果在開發中已經定義了一個名爲A的類,又想新建一個名爲B的類,但B中的大部分功能可以通過A實現,此時可以讓B繼承A,或者說B由A派生而來。
格式爲:class 派生類名: [繼承方式]基類名
繼承方式如下:
- 公有繼承:基類中的公有、私有成員在派生類中依舊保持原有的訪問屬性。
- 私有繼承:此時基類的公有成員和保護成員相當於派生類中的私有成員,派生類的成員函數能訪問,基類中的私有成員在派生類中是不可訪問的。
- 保護繼承:基類的公有保護成員在派生類中成爲保護成員,基類私有成員仍爲私有成員。主要作用是保護基類中的公有成員。
公有繼承示例:
.h文件
class Date {
public:
//Date();
void SetDate(int year, int month, int day);
//~Date();
void ShowDate();
private:
int year;
int month;
int day;
};
class Date1 : public Date //繼承自Date,其中public表示公有繼承
{
public:
void SetSec(int x); //新增成員函數
void GetFromDate();
private:
int sec; //新增成員變量
};
.cpp文件
#include "stdafx.h"
#include "lei.h"
#include <iostream>
using namespace std;
void Date::SetDate(int year, int month, int day)
{
this->year = year;
this->month = month;
this->day = day;
}
void Date::ShowDate()
{
cout << year << "年" << month << "月" << day << "日" << endl;
}
void Date1::SetSec(int x)
{
sec = x;
}
main函數
int main()
{
Date1 d1;
d1.SetDate(2018, 6, 2); //訪問基類中的兩個成員函數
d1.ShowDate();
return 0;
}
私有繼承示例如下:
.h文件
class Date {
public:
//Date();
void SetDate(int year, int month, int day);
//~Date();
void ShowDate();
private:
int year;
int month;
int day;
};
class Date1 : private Date //繼承自Date,其中private表示私有
{
public:
void GetFromDate();
};
.cpp文件
#include "stdafx.h"
#include "lei.h"
#include <iostream>
using namespace std;
void Date::SetDate(int year, int month, int day)
{
this->year = year;
this->month = month;
this->day = day;
}
void Date::ShowDate()
{
cout << year << "年" << month << "月" << day << "日" << endl;
}
void Date1::GetFromDate()
{
SetDate(2018, 6, 1); //通過Date1中的公有函數調用Date中的公有函數(此時 SetDate()和 ShowDate()相當於Date1中的私有成員函數)
ShowDate();
}
main函數
int main()
{
Date1 d1;
d1.GetFromDate();
return 0;
}
7.多態
多態指的是不同功能的函數可以用同一個函數名,不同對象調用這個函數時會產生不同的效果,多態分爲以下兩種。
- 靜態多態性(函數重載和運算符重載)
- 動態多態性(程序運行過程中動態確定,通過虛函數實現)
7.1 靜態多態性
7.1.1 函數重載
函數重載的示例如下
.h文件
#include<string>
using namespace std;
class Date {
public:
//Date();
void SetDate(int year, int month, int day);
//~Date();
void ShowDate();
void ShowDate(string str);
private:
int year;
int month;
int day;
};
.cpp文件
#include "stdafx.h"
#include "lei.h"
#include <iostream>
#include<string>
using namespace std;
void Date::SetDate(int year, int month, int day)
{
this->year = year;
this->month = month;
this->day = day;
}
void Date::ShowDate()
{
cout << year << "年" << month << "月" << day << "日" << endl;
}
void Date::ShowDate(string str)
{
cout << str << endl;
}
main函數
#include "stdafx.h"
#include<iostream>
#include "lei.h"
using namespace std;
int main()
{
Date d;
d.SetDate(2018, 6, 1);
d.ShowDate();
d.ShowDate("二零一八年六月一日");
return 0;
}
輸出爲
7.1.2 運算符重載
運算符重載可以修改現有的運算符,實現對類中數據進行操作的功能。
<返回類型說明符> operator <運算符符號>(<參數表>)
{
<函數體>
}
示例:
.h文件
#include<string>
using namespace std;
class Calculator {
public:
Calculator(); //用於value的初始化
void operator ++ (); //自增運算符
void operator--(); //自減運算符
int operator()(); //函數運算符
private:
unsigned int value;
};
.cpp文件
#include "stdafx.h"
#include "lei.h"
#include <iostream>
#include<string>
using namespace std;
Calculator::Calculator()
{
value = 0;
}
void Calculator::operator++()
{
if (value < 65535)
value++;
else
{
cout << "\noverflow" << endl;
}
}
void Calculator::operator--()
{
if (value > 0)
value--;
else
{
cout << "\nunderflow" << endl;
}
}
int Calculator::operator()()
{
return value;
}
.main函數
int main()
{
Calculator cal ;
for (int i = 0; i < 5; i++)
{
++cal; //調用自加運算符,執行類中value數據的自加
cout << "\n cal = " << cal(); //調用函數運算符,執行類中value數據的輸出
}
for (int i = 0; i < 5; i++)
{
--cal; ////調用自減運算符,執行類中value數據的自減
cout << "\n cal = " << cal();
}
return 0;
}
輸出如下
7.2 虛函數
在類的繼承中,不同派生類可以出現名字相同、參數個數和類型都相同而功能不同的函數,虛函數用以區分這些函數。
格式:virtual <返回類型> 函數名(<形參>).h文件
#pragma once
#include<string>
using namespace std;
class A {
public:
virtual void ShowMessage();//基類中聲明虛函數
};
class B :public A //B繼承A
{
public:
virtual void ShowMessage();
};
class C :public B //C繼承B
{
public:
virtual void ShowMessage();
};
.cpp文件
#include "stdafx.h"
#include "lei.h"
#include <iostream>
#include<string>
using namespace std;
void A::ShowMessage()
{
cout << "This is A!" << endl;
}
void B::ShowMessage()
{
cout << "This is B!" << endl;
}
void C::ShowMessage()
{
cout << "This is C!" << endl;
}
main函數
#include "stdafx.h"
#include<iostream>
#include "lei.h"
using namespace std;
int main()
{
A *a = new A();
B *b = new B();
C *c = new C();
a->ShowMessage();
b->ShowMessage();
c->ShowMessage();
return 0;
}
輸出如下