網龍C++遊戲訓練營培訓課程第一階段(下):類與對象、封裝、繼承和多態

(下)部分內容主要關注封裝、繼承和多態的操作。
傳送門:
第一階段(下):類與對象、封裝、繼承和多態

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.多態

多態指的是不同功能的函數可以用同一個函數名,不同對象調用這個函數時會產生不同的效果,多態分爲以下兩種。
  1. 靜態多態性(函數重載和運算符重載)
  2. 動態多態性(程序運行過程中動態確定,通過虛函數實現)

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;
}
輸出如下


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章