第一章:从面向过程到面向对象的过渡案例
PSO作业参考demo(C++)
内容说明:粒子群优化算法(PSO)作业源码参考,包含PSO类定义、类实现、辅助函数和主函数。
PSO.h — 粒子群算法类定义
#ifndef _PSO_H_
#define _PSO_H_
const int DIMENSION=30; //函数优化的维度(自变量个数)
/*--------------------------------------------------*
PSO类定义--粒子个体类
*---------------------------------------------------*/
class PSO
{
//------------------PSO类数据成员---------------
private:
//1.粒子个体信息
double x[DIMENSION];//粒子位置向量
double v[DIMENSION];//粒子速度向量
double fitness;//粒子适应度数值
//2.粒子局部最优信息
double pbestx[DIMENSION];//粒子局部最优位置
double pbestfitness; //粒子局部最优适应度数值
//3.粒子群全局最优信息(共享信息)
static double gbestx[DIMENSION];//全局最优位置
static double gbestFintness;//全局最优适应度值
//------------------PSO类函数成员---------------
public:
PSO();//构造函数
~PSO();//析构函数
//普通函数(获取粒子个体的相关信息)
double* getX();//获得粒子的位置向量
double* getV();//获得粒子的速度向量
double& getFitness();//获得粒子的适应度
double* getPbestX();//获得粒子的局部最优位置向量
double& getPbestFitness();//获得粒子的局部最优适应度数值
//普通函数:初始化位置和速度向量
void initi(double xmin, double xmax, double vmin, double vmax);
//普通函数:计算粒子的适应度(待优化的函数的值)
double computeFitness(double x[], int dim);
//普通函数:更新子局部最优和全局最优信息
void updatePbestX();//更新粒子个体局部最优位置
void updateGbestX();//更新粒子群体的全局最优位置
//普通函数:更新粒子的速度和位置向量-生成新的位置
void updateV(int iter);
void updateX(int iter);
//-----------------------------------------------------
//静态函数:获取全局最佳粒子信息
static double* getGbestX();//获得全局最佳位置向量
static double& getGbestFitness();//获得全局最佳适应度数值
//静态函数:输出全局最佳粒子信息
static void printGbestX();
static void printGbestFitness();
};
#endif
PSO.cpp — 粒子群算法类实现
#include <iostream>
#include <cmath>
#include <cstdlib>
#include "PSO.h"
#include "function.h"
using namespace std;
//初始化类中的静态数据成员
double PSO::gbestx[DIMENSION] = {0.0};//全局最优位置初始化
double PSO::gbestFintness=pow(2,1024);//全局最优适应度值初始化,一个较大的值
//外部全局变量导入本文件,以供使用
extern int MAX_ITER;
extern double xmax;
extern double xmin;
extern double vmax;
extern double vmin;
//--------------------PSO类的函数定义------------------------------
PSO::PSO()
{
//cout << "调用构造函数完成初始化" << endl;
}
PSO::~PSO()
{
//cout << "调用析构函数完成对象释放" << endl;
}
double * PSO::getX()
{
return x;//返回位置首地址
}
double * PSO::getV()
{
return v;
}
double & PSO::getFitness()
{
return fitness;
}
double * PSO::getPbestX()
{
return pbestx;
}
double & PSO::getPbestFitness()
{
return pbestfitness;
}
void PSO::initi(double xmin, double xmax, double vmin, double vmax)
{
//初始化粒子个体的位置和速度
for (int i = 0; i < DIMENSION; i++)
{
x[i] = xmin + (rand() / (32767 + 1.0)) *(xmax - xmin);
v[i] = vmin + (rand() / (32767 + 1.0))*(vmax - vmin);
}
//计算当前粒子最初的适应度
fitness = computeFitness(x,DIMENSION);
//初始化粒子最初的局部最优位置和适应度
for (int i = 0; i < DIMENSION; i++)
{
pbestx[i] = x[i];
}
pbestfitness = fitness;
}
//适应度:某个函数f的数值(计算结果越小说明对应的解越好)
double PSO::computeFitness(double x[], int dim)
{
fitness = sphere(x, dim);//函数Sphere作为测试函数,其他函数自行测试
//fitness = Rosenbrock(x, DIMENSION);//函数Rosenbrock作为测试函数
//fitness = Ackley(x, DIMENSION);
//fitness = Griewanks(x, DIMENSION);
return fitness;
}
//更新局部最优位置
void PSO::updatePbestX()
{
if (fitness<pbestfitness)
{
pbestfitness = fitness;
for (int i = 0; i < DIMENSION; i++)
{
pbestx[i] = x[i];
}
}
}
//更新全局最优位置
void PSO::updateGbestX()
{
if (pbestfitness<=gbestFintness)
{
gbestFintness = pbestfitness;
for (int i = 0; i < DIMENSION; i++)
{
gbestx[i] = pbestx[i];
}
}
else;
}
void PSO::updateV(int iter)
{
//更新公式参数
double w = 0.9 - 0.5*iter / MAX_ITER;
double c1 = 2.0;
double c2 = 2.0;
//注意r1,r2是随机生成的小数,需要将其放在for内,每次都产生新的随机数,随机性越高,求解精度越高
for (int i = 0; i < DIMENSION; i++)
{
v[i] = w * v[i] + c1 *rand()/(32767 + 1.0)*(pbestx[i] - x[i]) + c2 * rand() / (32767 + 1.0)*(gbestx[i] - x[i]);
//速度越界判断
if (v[i]<=vmin || v[i]>=vmax)
{
v[i] = (vmax - vmin)*rand() / (32767 + 1.0);
}
else continue;
}
}
void PSO::updateX(int iter)
{
for (int i = 0; i < DIMENSION; i++)
{
x[i] = x[i] + v[i];
//位置越界判断
if (x[i] <= xmin || x[i] >= xmax)
{
x[i] = xmin+(xmax - xmin)*double(rand()/RAND_MAX);
}
else continue;
}
}
//-----------------静态函数的定义--------------------
double * PSO::getGbestX()
{
return gbestx;
}
double & PSO::getGbestFitness()
{
return gbestFintness;
}
void PSO::printGbestX()
{
cout <<endl<<"输出当前最好的解:" << endl<<endl;
for (int dim = 0; dim < DIMENSION; dim++)
{
cout << "gbestX[" << dim << "] = " << gbestx[dim] << endl;
}
cout << endl;
}
void PSO::printGbestFitness()
{
cout << "全局最优解的精度: " << gbestFintness << endl;
cout << endl;
}
main.cpp — PSO主函数
/*************************************************
** 功能 : 粒子群优化算法演示
** 作者 : tsingke
** 时间 : 2019-11-22 / 10:54
***************************************************/
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <windows.h>
#include "PSO.h"
#include "function.h"
using namespace std;
//算法迭代参数设置
int POPSIZE = 40; //种群个体数目
int MAX_ITER = 7500; //迭代次数
double accuracy = 1e-60; //搜索精度,误差精度,可以自己改
//搜索范围设置(位置范围,速度范围)
double xmax = 10;
double xmin = -10;
double vmax = 10;
double vmin = -10;
bool success = 0;
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
srand((unsigned)time(NULL));//产生伪随机数种子
//1. 在堆上生成PSO类的对象数组,即粒子种群,共POPSIZE个个体
PSO *swarm=new PSO[POPSIZE];
//2. 初始化粒子群内所有粒子个体的信息(位置,速度,..等)
for (int i = 0; i < POPSIZE; i++)
{
swarm[i].initi(xmin,xmax,vmin,vmax);
}
//3. 循环迭代-搜索目标函数的全局最优解
cout << "---------------算法开始迭代-------------------" << endl;
for (int iter = 0; iter < MAX_ITER; iter++)
{
for (int id = 0; id < POPSIZE; id++)
{
swarm[id].updatePbestX();//更新个体局部最优位置
swarm[id].updateGbestX();//更新群体全局最优位置
swarm[id].updateV(iter);//更新个体速度
swarm[id].updateX(iter);//更新个体位置
swarm[id].computeFitness(swarm[id].getX(),DIMENSION);//计算个体适应度
}
//判断是否达到要求
if (PSO::getGbestFitness() <= accuracy)//达到设定的精度,中途输出结果,并停止后续迭代
{
cout << "搜索到符合精度的解(如下),算法停止搜索" << endl;
PSO::printGbestX(); //输出全局最优解向量
PSO::printGbestFitness(); //输出全局最优解的精度
success = 1;
break;//跳出循环,停止迭代
}
cout << "迭代到第" << iter << "代, 本代最佳适应度数值(误差精度)= " << PSO::getGbestFitness()<<endl;
}
//4. 输出实验结果(未达到设定精度,依然输出结果)
if (success==0)
{
PSO::printGbestX();//输出全局最优解向量
PSO::printGbestFitness();//输出搜索精度
}
//5. 释放申请的堆上的动态存储空间
delete[] swarm;
system("pause");
return 0;
}
function.h — 测试函数声明
#ifndef FUNCTION_H
#define FUNCTION_H
double sphere(double x[], int dim);
double Rosenbrock(double x[], int dim);
double Ackley(double x[], int dim);
double Griewanks(double x[], int dim);
#endif
function.cpp — 测试函数实现
#include <cmath>
#include <cstdlib>
#include "function.h"
//Sphere函数
double sphere(double x[], int dim)
{
double sum = 0;
for (int i = 0; i < dim; i++)
{
sum += x[i] * x[i];
}
return sum;
}
//Rosenbrock函数
double Rosenbrock(double x[], int dim)
{
double sum = 0;
for (int i = 0; i < dim - 1; i++)
{
sum += 100 * (x[i+1] - x[i]*x[i])*(x[i+1] - x[i]*x[i]) + (x[i]-1)*(x[i]-1);
}
return sum;
}
//Ackley函数
double Ackley(double x[], int dim)
{
double sum1 = 0, sum2 = 0;
for (int i = 0; i < dim; i++)
{
sum1 += x[i] * x[i];
sum2 += cos(2 * 3.1415926 * x[i]);
}
return -20 * exp(-0.2 * sqrt(sum1/dim)) - exp(sum2/dim) + 20 + 2.718281828;
}
//Griewanks函数
double Griewanks(double x[], int dim)
{
double sum = 0, prod = 1;
for (int i = 0; i < dim; i++)
{
sum += (x[i]*x[i])/4000;
prod *= cos(x[i]/sqrt(i+1));
}
return sum - prod + 1;
}
Chapt_1_ReadData:C++文件读取演示
内容说明:演示如何使用C++的文件输入输出流从文件中读取数据、排序后再写入另一个文件。
c++读取文件.cpp
#include <iostream>
#include <fstream>
#include <cstdlib> //qsort在此头文件中声明
using namespace std;
const int MAX_NUM = 1000;
int a[MAX_NUM]; //存放文件中读入的整数
int MyCompare(const void * e1, const void * e2)
{ //用于qsort的比较函数
return *((int *)e1) - *((int *)e2);
}
int main()
{
int total = 0;//读入的整数个数
ifstream srcFile("in.txt",ios::in); //以文本模式打开in.txt备读
if(!srcFile) { //打开失败
cout << "error opening source file." << endl;
return 0;
}
ofstream destFile("out.txt",ios::out); //以文本模式打开out.txt备写
if(!destFile) {
srcFile.close(); //程序结束前不能忘记关闭以前打开过的文件
cout << "error opening destination file." << endl;
return 0;
}
int x;
while(srcFile >> x) //可以像用cin那样用ifstream对象
a[total++] = x;
qsort(a,total,sizeof(int),MyCompare); //排序
for(int i = 0;i < total; ++i)
destFile << a[i] << " "; //可以像用cout那样用ofstream对象
destFile.close();
srcFile.close();
return 0;
}
chapt_1_ScoreSystem:学生成绩管理系统(C语言风格,面向过程)
内容说明:本章是第一章上机实验框架参考,用C语言风格的面向过程代码实现学生成绩管理系统,为后续转向OOP做铺垫。
main.c — 学生成绩管理系统主函数
#define _CRT_SECURE_NO_WARNINGS
/*************************************************
** 功能 : 学生成绩管理系统
** 作者 : Qingke Zhang/tsingke@sdnu.edu.cn
** 版本 : v1.0
** 版权 : GNU General Public License(GNU GPL)
/**************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "score.h"
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
printf("******************************\n");
printf(" 学生成绩管理分析系统 \n");
printf(" Qingke Zhang \n");
printf("******************************\n\n");
/*-1.变量初始化-*/
int N = 0; //学生总数
SS *pstu = NULL; //学生数组-结构体数组指针实现
//2.读取学生信息
pstu = readDataFromFile(&N);
/*-3.计算学生总成绩(总成绩 = 0.2*平时成绩 + 0.8*期末成绩)--*/
calcuScore(pstu, N);
/*-4.根据学生成绩排名-*/
sortScore(pstu, N);
/*-5.按照排名输出学生信息-*/
printOut(pstu, N);
/*-6.释放动态内存空间-*/
free(pstu);
system("pause");
return 0;
}
score.h — 学生管理头文件
/*************************************************
* Head File : SCORE.h
* File Usage : 学生管理系统头文件
* Create Time : v1.0
/**************************************************/
#ifndef __SCORE_H__
#define __SCORE_H__
#include <stdio.h>
/*----------------------------------*
学生信息-结构体设计
*-----------------------------------*/
typedef struct student
{
char number[10]; //学号
char name[10]; //姓名
float dailyScore; //平时成绩
float finalScore; //期末成绩
float generalScore; //总评成绩
}SS;
/*---------------函数声明-------------------*/
//1.读取学生基本数据
void readData(SS stu[], int N);
SS* readDataFromFile(int *N);
//2.计算N个学生各自总成绩
void calcuScore(SS stu[], int N);
//3.根据总评成绩排名
void sortScore(SS stu[], int N);
//4.按照一定的格式输出N个学生的完整信息
void printOut(SS stu[], int N);
#endif
score.c — 学生管理函数实现
/*************************************************
** 源文件 : score.c
** 功能说明 : Function Definitions
** 创建版本 : v1.0
/**************************************************/
/*----------------头文件--------------*/
#define _CRT_SECURE_NO_WARNINGS
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "SCORE.h"
/*----------------函数定义-------------*/
//1.1手动输入学生基本数据
void readData(SS stu[], int N)
{
printf("请按照如下格式输入学生信息:学号,姓名,平时成绩,期末成绩\n");
for (int i = 0; i < N; i++)
{
printf("第%d个学生:", i + 1);
scanf("%s %s %f %f", &stu[i].number, &stu[i].name, &stu[i].dailyScore, &stu[i].finalScore);
printf("\n");
}
printf("------成绩录入完毕!--------\n");
}
//1.2从文件里读取学生基本数据
SS* readDataFromFile(int *N)
{
printf("\n\n------第一步: 从文件读取学生的成绩信息--------\n\n");
SS *stu;// 开辟新空间,存取文件中的每个学生信息
FILE *fp = NULL;
int count = 0;
int index = 0;
fp = fopen("data.txt", "r");
//1.获取学生数目
if (fp != NULL)
{
fscanf(fp, "%d", &count);
*N = count;
}
else
{
printf("failed to open the info file\n");
getchar();
}
printf("学生数目为:%d\n", count);
//2.给所有学生分配存储空间
stu = (SS*)malloc(count * sizeof(SS));
//3.读取每条学生的信息
while ((!feof(fp)))
{
//读入文件数据到内存
fscanf(fp, "%s%s%f%f\n", (stu[index].number), (stu[index].name), &stu[index].dailyScore, &stu[index].finalScore);
//输出排序后的学生信息
printf("* 学号:%s 姓名:%s 平时成绩:%4.2f分 期末成绩:%4.2f分\n", (stu[index].number), (stu[index].name), stu[index].dailyScore, stu[index].finalScore);
index++;
}
getchar();
fclose(fp);
return stu;
}
//2.计算N个学生各自的总评成绩
void calcuScore(SS stu[], int N)
{
printf("\n\n------第二步: 计算每个学生的总评成绩--------\n\n");
for (int i = 0; i < N; i++)
{
stu[i].generalScore = 0.2*stu[i].dailyScore + 0.8*stu[i].finalScore;
printf("* 学号:%s 姓名:%s 总成绩:%4.2f分\n", (stu[i].number), (stu[i].name), stu[i].generalScore);
}
getchar();
}
//3.根据总评成绩排名
int cmpBigtoSmall(const void *a, const void *b)
{
SS *aa = (SS *)(a);
SS *bb = (SS *)(b);
if ((*aa).generalScore < (*bb).generalScore) return 1;
else if ((*aa).generalScore > (*bb).generalScore) return -1;
else
return 0;
}
void sortScore(SS stu[], int N)
{
qsort(&(stu[0]), N, sizeof(stu[0]), cmpBigtoSmall);
}
//4.按照一定的格式输出N个学生的信息
void printOut(SS stu[], int N)
{
printf("\n------第三步: 根据总成绩输出学生排名信息!------\n\n");
for (int i = 0; i < N; i++)
{
printf("第%d名信息 学号:%s 姓名:%s 总成绩:%4.2f分\n", i + 1, &(stu[i].number[0]), &(stu[i].name[0]), stu[i].generalScore);
}
getchar();
}
data.txt — 测试数据
6
201720398 zhang 84.7 96
201720224 wang 78 86
201711034 zhao 80 86
201711045 liu 69 75
201724397 TomHanks 85 90
201700925 Jeny 90 96
第二章:C++与C(C++新增语法特性)
内容说明:本章展示C++相对C新增的语法特性,包括内联函数、命名空间、new/malloc、引用、异常处理、const、默认参数等。
inlineFunction.cpp — 内联函数
/*************************************************
** 功能 : 内联函数的使用
** 作者 : tsingke
** 时间 : 2019-9-24 / 00:42
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <ctime>
#include <cmath>
using namespace std;
const int run = 100000000;
int multiply_1(int x, int y)
{
return x*y;
}
inline int multiply_2(int x, int y)
{
return x*y;
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
int t=0;
int a = 1;
int b = 2;
/*----------------------------------*
普通函数调用时间统计
*-----------------------------------*/
int ss_1, ss_2;
clock_t start_1, end_1;
start_1 = clock();
while (t<run)
{
ss_1 = multiply_1(a++, b++);
//cout << a << "^2 + " << b << "^2 = " << ss << endl;
t++;
}
end_1 = clock();
cout << "普通函数执行总时间: " <<1.0*(end_1 - start_1) << endl;
/*----------------------------------*
内联函数调用时间统计
*-----------------------------------*/
clock_t start_2, end_2;
start_2 = clock();
t = 0;
while (t < run)
{
ss_2 = multiply_2(a++, b++);
//cout << a << "^2 + " << b << "^2 = " << ss << endl;
t++;
}
end_2 = clock();
cout << "内联函数执行总时间: " << 1.0*(end_2 - start_2) << endl;
system("pause");
return 0;
}
namespace.cpp — 命名空间
/*************************************************
** 功能 : namespace
** 作者 : tsingke
** 时间 : 2019-9-23 / 21:33
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
#include <string>
using namespace std;
namespace one
{
int id;
double salary;
}
namespace two
{
int id;
double salary;
}
namespace three
{
int id;
double salary;
string address;
}
/*----------------------------------*
Main Function
*-----------------------------------*/
using namespace one;
int main()
{
/*-全部导入法-*/
id = 2018;
salary = 100000;
/*-随用随取法-*/
two::id = 2019;
two::salary = 50000;
/*-部分导入法-*/
using three::id;
id = 100;
cout << "one::id = "<< one::id << endl;
id = 999999;
cout << "two::id = " <<id<< endl;
cout << "one::id = "<< one::id << endl;
//address = "sdnu";
three::address = "sdnu";
cout << three::address << endl;
system("pause");
return 0;
}
new-malloc.cpp — new与malloc对比
/*************************************************
** 功能 : new和malloc的使用演示
** 作者 : tsingke
** 时间 : 2019-10-7 / 12:34
***************************************************/
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <windows.h>
using namespace std;
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
/*----------------------------------*
使用malloc 和 free
*-----------------------------------*/
int *p1;
p1= (int*)malloc(sizeof(int) * 10);
memset(p1, 0, 10*sizeof(int));//初始化为0
for (int i = 0; i < 10; i++)
{
cout << p1[i] << " ";
}
cout << endl;
//初始化
for (int i = 0; i < 10; i++)
{
p1[i] = i;
cout << (p1[i]) << " ";
}
cout << endl;
/*-输出各个元素的物理存储地址-*/
for (int i = 0; i < 10; i++)
{
cout << "地址: " << &p1[i] << endl;
}
cout << endl;
free(p1);
int *p3 = (int*)calloc(10, sizeof(int));
for (int i = 0; i < 10; i++)
{
cout << p3[i] << " ";
}
cout << endl;
/*----------------------------------*
使用new 和 delete
*-----------------------------------*/
int *p2;
p2 = new int[10];
for (int i = 0; i < 10; i++)
{
p2[i] = i*i;
cout << p2[i] <<" ";
}
cout << endl;
/*-输出各个元素的物理存储地址-*/
for (int i = 0; i < 10; i++)
{
cout << "地址: " << &p2[i] << endl;
}
delete[] p2;
/*----多维数组的申请-----*/
int(*pt)[5] = new int[4][5];//pt[4][5]
//初始化的方法
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
pt[i][j] = i * j;
cout << pt[i][j]<<" ";
}
cout << endl;
}
int(*ptt)[4][6] = new int[3][4][6];//ptt[3][4][6]
delete[] pt;
delete[] ptt;
system("pause");
return 0;
}
referenceDemo1.cpp — 引用基础
/*************************************************
** 功能 : 引用的用法
** 作者 : tsingke
** 时间 : 2019-10-8 / 14:50
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
void swap(int &x, int &y)
{
int temp;
temp = x;
x = y;
y = temp;
}
int& func(int &x, int &y)
{
int x = x + y;
return x;
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
int a = 88;
int b = 66;
int &r = a;
int &rrrrr = a;
//r = 99;
cout << "a= " <<a<< endl;
cout << "r= " <<r<< endl;
cout << "a的地址=" << &a << endl;
cout << "r的地址=" << &r << endl;
cout << "rrrr的地址=" << &rrrrr << endl;
cout << "a= " << a << endl;
cout << "b= " << b << endl;
int c = a+b;
swap(c, b);
cout << "a= " << a << endl;
cout << "b= " << b << endl;
func(a, b);
int xx= func(a, b) + 18;
func(a, b) = 4;//x=4;
system("pause");
return 0;
}
referenceDemo2.cpp — 引用深入
/*************************************************
** 功能 : 引用的使用演示案例demo
** 作者 : tsingke
** 时间 : 2019-10-8 / 10:08
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
double sum(int x, int &y)
{
x++;
y++;
return x + y;
}
int& sumref(int x,int &y)
{
y = x + y;
return y;
//注意:不要返回局部变量的引用,因为局部变量离开所在函数就被系统释放回收了,即使起别名也没有任何使用价值.
// 可以返回某个类型为引用的形参,例如这里的y就是一个引用形参类型,可以返回.
}
int func(int *p, int &r,int o)
{
*p = 666;//通过指针改变指向的数值
r = 888;//通过引用改变指向的数值
o = 999;
cout << "指针*p的数值= " << *p << endl;
cout << "引用r的数值= " << r << endl;
cout << "整型o的数值= " << o << endl;
return 0;
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
//1. 什么是引用:变量的别名
int a1 = 100;
int a2 = 200;
int &r = a1;//声明时就要给引用初始化
r = a2;
cout << "a的地址:" << &a1 << endl;
cout << "r的地址:" << &r << endl;
//2.哪些量不可以是引用
//void va; //不可以建立void变量的引用
//int &&r = a;//不可以建立引用的引用
//int & *p = a;//不允许使用指向指针的引用
//int & arry[10] = a;//不允许使用引用的数组
//3. 引用的作用1: 做函数的形参,做函数的返回类型
sum(a1, a2);
cout << "a1的数值= " << a1 << endl;
cout << "a2的数值= " << a2 << endl;
//4. 引用的作用2:作为函数的返回类型(例如:cin>>x执行完后返回的是cin对象的引用,还是cin)
sumref(a1, a2);//独立的函数调用语句
int s = sumref(a1, a2) + 8;//引用作为操作数
sumref(a1, a2) = 3000;//引用作为左边的数值
//5. 引用和指针的区别
//引用:变量的别名, 本身直接操作指向的数据
//指针:带有类型的地址,远程间接操作指向的数据
int m = 1;
int n = 2;
int o = 3;
func(&m, n,o);
cout << "m = " << m << " n= " << n << endl;
system("pause");
return 0;
}
try-catch_1.cpp — try-catch原理剖析
/*************************************************
** 功能 : try-catch 原理剖析
** 作者 : tsingke
** 时间 : 2019-10-7 / 20:17
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
void func1(int a);
void func2(int a);
void func3(int a);
void func4(int a);
//函数调用关系: fun1-->func2-->func3-->func4
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
int x;
cout << "请输入整数x= ";
cin >> x;
try
{
func1(x);
}
catch (const int e)
{
cout << "主函数内处理异常" << endl;
}
system("pause");
return 0;
}
//-------------------子函数定义--------------------
void func1(int a)
{
if (a == 1)
{
throw 1;
}
try
{
func2(a);
}
catch (int e)
{
cout << "func1 内处理异常" << endl;
}
cout << " i am func1" << endl;
}
void func2(int a)
{
if (a == 2)
{
throw 2;
}
try
{
func3(a);
}
catch (int e)
{
cout << "func2 内处理异常" << endl;
}
cout << " i am func2" << endl;
}
void func3(int a)
{
if (a == 3)
{
throw 3;
}
try
{
func4(a);
}
catch (int e)
{
cout << "func3 内处理异常" << endl;
}
cout << " i am func3" << endl;
}
void func4(int a)
{
if (a == 4)
{
throw 4;//如果引发异常,下面的输出语句将不会执行
}
cout << " i am func4" << endl;
}
try-catch_2.cpp — try-catch课堂演示
/*************************************************
** 功能 : try-catch课堂演示
** 作者 : tsingke
** 时间 : 2019-10-7 / 12:51
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
double add(int a, int b)
{
if (a+b == 0)
{
throw -1;
cout << "-1"<< endl ;
}
return double(a + b);
}
double subtraction(int a, int b)
{
if (a - b == 0)
{
throw - 2;
cout << "-2" << endl;
}
return double(a - b);
}
double multiplication(int a, int b)
{
if (a * b == 0)
{
throw - 3;
cout << "-3" << endl;
}
return double(a * b);
}
double divide(int a, int b)
{
if (b == 0)
{
throw - 4;
cout << "-4"<< endl ;
}
return double(1.0*a / b);
}
double rootsum(int a,int b)
{
if (a<0 && b<0)
{
throw -1.2;
cout << "-5" << endl;
}
return double(sqrt(a)+sqrt(b));
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
cout << "try- catch 使用演示" << endl ;
int a, b;
do
{
try
{
cout << endl<< "------输入两个数,输出他们的四则运算结果-----" << endl;
cout << "a = "; cin >> a;
cout << "b = "; cin >> b;
cout << "a+b = " << add(a, b) << endl;
cout << "a-b = " << subtraction(a, b) << endl;
cout << "a*b = " << multiplication(a, b) << endl;
cout << "a/b = " << divide(a, b) << endl;
cout << "sqrt(a)+sqrt(b)= " << rootsum(a, b) << endl;
}
catch (const int e)
{
switch (e)
{
case -1: cout << "异常发生: a+b == 0"; break;
case -2: cout << "异常发生: a-b == 0"; break;
case -3: cout << "异常发生: a*b == 0"; break;
case -4: cout << "异常发生: a/b == null"; break;
default:
break;
}
}
catch (const double f)
{
cout << f << endl;
cout << "异常发生: a<0 或b <0 " << endl;
}
} while (1);
system("pause");
return 0;
}
constDemo.cpp — const基础
/*************************************************
** 功能 : const demo
** 作者 : tsingke
** 时间 : 2019-9-24 / 08:33
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
int sum(const int *p1, const int *p2)
{
//*p1 = 222;
return (*p1 + *p2);
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
int a = 666;
int b = 888;
int c=sum(&a, &b);
cout << "c= " << c << endl ;
system("pause");
return 0;
}
const与指针.cpp — const与指针
#include <iostream>
using namespace std;
int main()
{
int i=100;
int j=200;
//1.指向常量的指针:指向的量是常量,故*p1不可变,但p1可变
#if 1
const int *p1;
*p1 = j;//错误
p1=&j; //正确
#endif
//2.常指针:指针自己是常量, 故p2不可变, 但*p2可变
#if 1
int* const p2=&i;
p2 = &j; //错误
*p2=j; //正确
#endif
//3.指向常量的常指针: 指针是常量,指针指向的也是常量,故都不能修改。
#if 1
int const * const p3 =&i;
p3=&j;//错误
*p3=j;//错误
#endif
return 0;
}
defaultArgument_1.cpp — 默认形参(基础)
/*************************************************
** 功能 :默认形参函数演示
** 作者 : tsingke
** 时间 : 2019-10-8 / 14:29
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
void func(int a, int b,int c)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
void func_1(int a, int b=600, int c=800)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
int a = 1;
int b = 2;
int c = 3;
int a_1 = 3;
//func(a, b, c);
func_1(a);
func_1(a, b);
func_1(a, b, c);
system("pause");
return 0;
}
defaultArgument_2.cpp — 默认形参(深入)
/*************************************************
** 功能 : 函数默认形参演示
** 作者 : tsingke
** 时间 : 2019-9-23 / 23:29
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
void plot(int x , int y , int z = 0, char color = 'B');
//void plot(int x, int y, int z, char color)
//{
//
// cout << "坐标x= " << x << endl;
// cout << "坐标y= " << y << endl;
// cout << "坐标z= " << z << endl;
//
// cout << "颜色 c= " <<color << endl ;
//
//}
//void plot(int x=0, int y=1, int z=0, char color='B')
//{
//
// cout << "------图形的基本信息如下所示-------" << endl ;
// cout << "坐标x= " << x << endl;
// cout << "坐标y= " << y << endl;
// cout << "坐标z= " << z << endl;
//
// cout << "颜色 c= " << color << endl;
//
//}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
int a = 3, b = 4, c = 5;
char color = 'R';
plot(a, b, c, color);//一一对应的方式
plot(a, b);//
system("pause");
return 0;
}
//定义带默认形参的函数时,不要带上默认值,只在声明时带上!!!!
void plot(int x, int y, int z, char color)
{
cout << x << y << z << color<< endl;
}
第三章:类与对象(上)
内容说明:本章进入面向对象编程核心——类与对象,包含this指针、构造函数、类对象使用、友元函数、浅拷贝与深拷贝。
this.cpp / constructor.cpp — 构造函数课堂演示
/*************************************************
** 功能 : 构造函数课堂演示
** 作者 : tsingke
** 时间 : 2019-10-21 / 18:18
***************************************************/
#include <iostream>
#include <cstdlib>
using namespace std;
class date
{
public:
void inition(int y,int m, int d);
date(); //无参构造函数
date(int y, int m=1, int d=1);//有参构造函数(可以给定默认值)
date(const date &r);//拷贝构造函数
void display();
~date();
private:
int year;
int month;
int day;
};
void date::inition(int y, int m, int d)
{
this->year =y;
this->month =m;
this->day=d;
}
date::date()
{
cout << "无参构造函数被调用" << endl;
}
date::date(int y,int m, int d)
{
year = y;
month = m;
day = d;
cout << "有参构造函数被调用" << endl;
}
date::date(const date & r)
{
this->year = r.year;
this->month = r.month;
this->day = r.day;
cout << "拷贝构造函数被调用" << endl;
}
void date::display()
{
cout<<year<<"-"<<month<<"-"<<day<<endl;
//cout<<"指针this指向地址:"<<this<<endl;
}
date::~date()
{
cout << "*析构函数调用:" <<this<<endl;
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
date a;//对象a
cout<<"对象a的地址:"<<&a<<endl;
a.display();
date b(2019);//对象b
b.display();
date c(b);//对象c
c.display();
return 0;
}
构造函数的使用(课堂范例).cpp
/*************************************************
** 功能 : 构造函数的使用
** 作者 : tsingke
** 创建 : 2020-11-2
** 版权 : tsingke@sdnu.edu.cn
**************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
class Date
{
private:
int year, month, day;
public:
Date()
{
cout << "无参构造函数被调用!" << endl;
}
Date(int year, int month, int day)
{
this->year = year;
this->month = month;
(*this).day = day;
cout << "普通构造函数被调用!" << endl;
}
Date(const Date& r)
{
this->year = r.year;
this->month = r.month;
this->day = r.day;
cout << "拷贝构造函数被调用!" << endl;
}
~Date()
{
cout << "~析构函数被调用(回车继续)!" << endl;
getchar();
}
};
//全局函数,返回类的对象类型
Date func(Date val)
{
cout << "func()is called" << endl;
return val;//调用拷贝构函,情形三
}
/*----------------------------------*
* Main Function
*-----------------------------------*/
int main()
{
Date lastday;//调用无参构函
Date today(2020, 11, 1);//调用有参构函
Date tommory(today);//调用拷贝构函(情形一)
func(tommory);//调用拷贝构函(情形二)
today = Date(2021,11,11);//调用普通有参构函,不会调用拷贝构函
system("pause");
return 0;
}
triangleDemo.cpp — 三角形类的演示
/*************************************************
** 功能 : 类的演示
** 作者 : tsingke
** 时间 : 2019-10-15 / 15:12
***************************************************/
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <windows.h>
using namespace std;
class triangle
{
private:
double a;
double b;
double c;
public:
void inti(int, int, int);
bool isTriangle();
double perimeter();
double area();
int typeTriangle();
void ModifyA(int);
};
bool triangle::isTriangle()
{
if ((a + b) > c && (a + c) > b && (b + c) > a)
{
return true;
}
else
return false;
}
void triangle::inti(int s1, int s2, int s3)
{
a = s1;
b = s2;
c = s3;
if (isTriangle() == false)
{
cout << "无法构成三角形,退出程序!" << endl;
exit(0);
}
}
double triangle::perimeter()
{
return a + b + c;
}
double triangle::area()
{
double p = perimeter() / 2.0;
return sqrt(p*(p - a)*(p - b)*(p - c));
}
int triangle::typeTriangle()
{
if (pow(a, 2) + pow(b, 2) == pow(c, 2))
{
return 1;
}
else if (pow(a, 2) + pow(b, 2) < pow(c, 2))
{
return 2;
}
else
{
return 3;
}
}
void triangle::ModifyA(int s)
{
a = s;//间接修改边长a的数值
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
triangle t;
int ta, tb, tc;
//t.a = 666;//无法直接访问私有数据
t.ModifyA(6666);
cout << "pleaes input three edges: " << endl;
cin >> ta;
cin >> tb;
cin >> tc;
t.inti(ta, tb, tc);
cout << "周长=" << t.perimeter() << endl;
cout << "面积= " << t.area() << endl;
if (t.typeTriangle() == 1)
{
cout << "直角三角形" << endl;
}
else if (t.typeTriangle() == 2)
{
cout << "锐角三角形" << endl;
}
else
cout << "钝角三角形" << endl;
system("pause");
return 0;
}
类对象的使用-一码知天下.cpp
/*************************************************
** 功能 : 对象的使用
** 作者 : tsingke
** 时间 : 2019-11-4 / 18:02
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
class date
{
//1.类的变量记心间
private:
int year;
int month;
int day;
public:
//2. 三构一析放在前
date();
date(int year, int month, int day);
date(const date &r);
~date();
//3.普函定义按需添
int getYear();
int getMonth();
int getDay();
void setYear(int y);
void setMonth(int m);
void setDay(int d);
void display();
};
//---------------类成员函数的实现----------------------
date::date()
{
cout << "++无参构造函数被调用++" << endl;
year = 2019;
month = 01;
day = 01;
}
date::date(int year, int month, int day)
{
cout << "++有参构造函数被调用++" << endl;
this->year = year;
this->month = month;
this->day = day;
}
date::date(const date & r)
{
this->year = r.year;
this->month = r.month;
this->day = r.day;
}
date::~date()
{
cout << "--析构函数被调用--" << endl;
}
int date::getYear()
{
return year;
}
int date::getMonth()
{
return month;
}
int date::getDay()
{
return day;
}
void date::setYear(int y)
{
this->year = y;
}
void date::setMonth(int m)
{
this->month = m;
}
void date::setDay(int d)
{
this->day = d;
}
void date::display()
{
cout << year << "年" << month << "月" << day << "日" << endl;
}
//==================全局函数=========================
void print(date &r)
{
cout << r.getYear() << "年" << r.getMonth() << "月" << r.getDay() << "日" << endl;
}
//对象作为参数(对象,对象指针,对象引用)
void objectAsArgument(date t, date * p, date & r)
{
//传值形式无法修改原对象内容,但可以访问到原对象内相同的数据
t.setYear(2050);
t.setMonth(10);
t.setDay(24);
//通过指针修改原对象内容
p->setYear(2035);
p->setMonth(6);
p->setDay(1);
//通过引用修改原对象内容
r.setYear(2050);
r.setMonth(10);
r.setDay(24);
}
/*----------------------------------*
Main Function
*-----------------------------------*/
//使用方法: 把#if 后面的0改成1即可调试对应区域代码
int main()
{
#if 0
//----------------------第一块演示: 对象的数组----------------------------------
//a1.栈对象数组的定义
//date array_1[3];//调用无参构造函数
//date array_2[3] = { date(2019,10,1),date(2019,10,2) };//按需调用构造函数
//a2.堆对象数组的定义
//date *parray_1 = new date[3];//调用无参构造函数
date *parray_2 = new date[3];//调用无参构造函数
date *temp = parray_2;
parray_2[0] = date(2020, 1, 1);
parray_2[1] = date(2020, 1, 2);
parray_2[2] = date(2020, 1, 3);
//b. 对象数组元素访问对象成员的方式(2种)
for (int i = 0; i < 3; i++)
{
//array_1[i].display();//直接访问对象成员法
//array_2[i].display();//直接访问对象成员法
//(parray_1++)->display();//间接访问对象成员法
(parray_2++)->display();//间接访问对象成员法
//循环体执行完本语句后,如果在程序里用delete[]parray_2就会报错,因为
//此时parray_2不再指向动态数组的首地址,而是第3个元素的地址,所以
//建议使用直接访问的方式比较稳妥!!!!
}
delete[]temp;
#endif
#if 0
//---------------------第二块演示:对象的指针----------------------------------
date s1;
//1. 探索指针的初始化,建议定义指针变量时务必对其进行初始化,否则后患无穷!!
date *p = NULL;//如果这里令 date *p=1,就会报错,这里的NULL实际是0,本质上是个地址,即NULL=0=00000000
cout << "p指向到哪里:" << p << endl;
p = 0;//这里的0,本质上是个地址,即0=00000000,如果改成p=1,报错,因为1不是内存地址.
cout << "p指向到哪里:" << p << endl;
//2.指针的两种用法
p = &s1;
s1.getYear();
(*p).getYear();
p->getYear();
#endif
#if 0
//----------------------第三块演示:对象的引用----------------------------------
date today;
date &r = today;
today.display();
r.display();
date tomorrow(2030, 10, 1);
//r自始至终都是today的引用,不会变化
//通过改变today或r的值,彼此内容都会发生变化
r = tomorrow;
today.display();
//对象引用的核心作用:作为函数的形参
print(today);
#endif
#if 0
//----------------------第四块演示:.对象作为参数(对象,对象指针,对象引用)----------------------------------
date day_1(1970, 1, 1);
date day_2(1970, 1, 1);
date day_3(1970, 1, 1);
objectAsArgument(day_1, &day_2, day_3);
day_1.display();//day_1对象没有被修改(数值)
day_2.display();//day_2对象已经被修改(指针)
day_3.display();//day_3对象已经被修改(引用)
#endif
//-----------------------------------Over---------------------------------------------------------------
system("pause");//如果想查看析构函数被调用情况,请单步调试,一直F10即可.
return 0;
}
classDemo.cpp — 类的综合演示
/*************************************************
** 功能 : 类的演示
** 作者 : tsingke
** 时间 : 2019-10-15 / 08:58
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
//设计一个学生结构体
struct student_s
{
string name;
int id;
int age;
double high;
double weight;
double salary;
};
class date
{
public:
int year;
private:
int month;
int day;
public:
void display()
{
cout << year << "年" << month << "月" << day << "日" << endl;
}
void initi(int y, int m, int d);
void modifyear();
int getmonth()
{
return month;
}
};
void date::initi(int y,int m,int d)
{
year = y;
month = m;
day = d;
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
struct student_s wang;
wang.name = "wanger";
wang.id = 2018;
wang.age = 20;
wang.high = 1.75;
wang.weight = 60;
wang.salary = 7000;
date today;
today.initi(2019, 10, 15);
today.display();
today.year = 2020;
cout<<today.getmonth()<<endl;
system("pause");
return 0;
}
Distribution of the objects and object members.cpp — 对象分布规律
/*************************************************
** 功能 : 对象的访问
** 作者 : tsingke
** 时间 : 2019-10-21 / 22:27
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
class date
{
private:
int year;
int month;
int day;
public:
void setDate(int y, int m, int d)
{
year = y;
month = m;
day = d;
}
void display()
{
cout << "year=" << year << " month= " << month << " day=" << day << endl;
}
void address()
{
cout << "year的地址:" << &this->year << endl;
cout << "month的地址:" <<& this->month << endl;
cout << "day的地址:" << & this->day<< endl;
}
};
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
date a;
date *p =&a;
//1.对象直接访问其内容
a.setDate(2019, 10, 22);
a.display();
(*p).display();
//2. 指针间接访问对象内容
p->display();
//3. 探索类对象内数据成员的存放规律
date b;
date c;
b.setDate(2019, 12, 31);
c.setDate(2020, 12, 31);
cout << endl;
//3.分析对象的分布规律(高地址-低地址)
cout << "对象b的地址" << &b << endl;
cout << "对象c的地址" << &c << endl;
cout << endl;
//4.分析对象内变量的分布规律(低地址--高地址)
b.address();
//c.address();
system("pause");
return 0;
}
friend-global function.cpp — 友元全局函数
#include <iostream>
using namespace std;
class date
{
int year;
int month;
int day;
public:
date(int y,int m,int d) ;
~date();
void display();
friend void birthdayCheck(date &r1,date &r2);// 友元"流浪"函数的声明
};
date::date(int y, int m, int d)
{
this->year=y;
this->month=m;
this->day=d;
cout<<"this is a constructor function " <<endl;
}
date::~date()
{
cout<<"this is a deconstrucor"<<endl ;
}
void date::display()
{
cout<<year<<"年-"<<month<<"月-"<<day<<"日"<<endl;
}
void birthdayCheck(date &r1,date &r2)
{
if((r1.year==r2.year)&&(r1.month==r2.month)&&(r1.day==r2.day))
{
cout<<"是同一天生日"<<endl;
}
else
{
cout<<"不是同一天生日"<<endl;
}
}
int main()
{
date zhang(2000,10,1);
date wang(2000,10,1);
zhang.display();
wang.display();
birthdayCheck(zhang,wang);
return 0;//
}
shallow-deep — 浅拷贝与深拷贝
student.h
#pragma once
class student
{
private:
int id;
char *name; //申请动态内存的信号
public:
//1. 构造函数,析构函数
student(int id, const char *user_name);
student(const student &r);
~student();
//2. 普通函数
void display();
};
student.cpp
#include "student.h"
#include <iostream>
using namespace std;
student::student(int id, const char *user_name)
{
cout << "构造函数被调用" << endl;
this->id = id;
if (user_name!=NULL)
{
int len = strlen(user_name);
name = new char[len + 1];
strcpy(name, user_name);
}
}
student::student(const student & r)
{
this->id = r.id;
// this->name = r.name;//浅拷贝<-----栈上操作
if (r.name!=NULL)//深度拷贝<---堆上操作
{
int len = strlen(r.name);
this->name = new char[len + 1];
strcpy(this->name, r.name);
}
}
student::~student()
{
cout << "--析构函数被调用--" << endl;
if(name != NULL)
{
delete[] name;
}
}
void student::display()
{
cout << "学号id = " << id << endl;
cout << "姓名name= " << name << endl;
}
main.cpp
/*************************************************
** 功能 : 浅拷贝-深拷贝代码演示
** 作者 :
** 版本 : 2019-10-29 / 19:18
** 版权 : GNU General Public License(GNU GPL)
/**************************************************/
#include <iostream>
#include <cstdlib>
#include "student.h"
using namespace std;
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
char *name = new char[20];
strcpy(name, "bill gates");
student zhang(2019,name);
student wang = zhang;//调用系统默认的拷贝构造函数
zhang.display();
wang.display();
system("pause");
return 0;
}
shallow-deep-copy — 另一种浅拷贝与深拷贝实现
student.h
#ifndef STUDENT_H
#define STUDENT_H
//析构函数的作用:
/***
*
* 完成对象销毁前的清理工作,释放构造器申请的堆空间
* 无返回类型
* 自动被调用
* 不能被重载,因为析构函数本身没有任何参数,所以"同名不同参"的条件永远无法被满足)
*/
class student
{
public:
student();
student(char*na,int age,int gender);
student(const student &r);
~student();
void display();
private:
char *name;
int age;
bool gender;
};
#endif // STUDENT_H
student.cpp
#define _CRT_SECURE_NO_WARNINGS
#include "student.h"
#include<cstring>
#include<iostream>
using namespace std;
// 使用构造函数完成对象的初始化
student::student()
{
}
student::student(char *na, int age, int gender)
{
cout << "+构造函数被调用" << endl;
if (na != NULL)
{
int len = strlen(na);
this->name = new char[len + 1];
strcpy(this->name, na);
}
this->age = age;
this->gender = gender;
}
student::student(const student &r)
{
cout << "+拷贝构造函数被调用" << endl;
//系统默认对位拷贝
//this->name = r.name;//浅拷贝,仅涉及栈上的数据对位拷贝,不涉及堆
if (r.name!=NULL)//深度拷贝--仅仅针对有堆数据拷贝的情况
{
this->name = new char[strlen(r.name) + 1];
strcpy(name, r.name);
}
this->age = r.age;
this->gender = r.gender;
}
student::~student()
{
//删除堆空间
if (this->name != NULL)
{
delete[] name;
}
cout << "~析构函数被调用" << endl;
}
void student::display()
{
cout << "name = " << name << endl;
cout << "age = " << age << endl;
cout << "gender= " << this->gender << endl;
}
main.cpp
#include <iostream>
#include "student.h"
using namespace std;
int main()
{
char *name =new char[20];
name="Bill Gates";
student stu1(name,60,1);
stu1.display();
student stu2=stu1;
stu2.display();
return 0;
}
第四章:类与对象(下)— static 与 const
内容说明:本章深入探讨类的static成员和const成员,包含const静态与全局常量、常成员函数、常对象、静态成员变量、静态成员函数。
const — 常量
const_demo_1(常量const本质剖析).cpp
/*************************************************
** 功能 : const本质:const栈常量与const全局区常量 能否被修改?
** 作者 : tsingke
** 时间 : 2019-11-11 / 23:36
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
const int global = 100;
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
#if 1
//情形1: const修饰的栈上的常量,通过指针可以间接实现对其修改
const int local = 10;//下面程序所有的local在编译时都被替换为10
cout << "const local = " << local << endl;
//意图通过指针修改这个常量
int *p1 = (int*)(&local);
*p1 = 20;
cout << "const local = " << *p1 << endl;
cout << "local地址 = " << &local << endl;
cout << "p1指向的地址 = " << p1 << endl;
#endif
//---------------------------------------------
#if 0
//情形2:const修饰的全局区上的常量,通过指针无法对其进行修改(编译时会报异常)
int *p2 = (int*)(&global);
cout << "const global = " << global << endl;
*p2 = 200;
cout << "const global = " << *p2 << endl;
cout << "global地址 = " << &global << endl;
cout << "p2指向的地址 = " << p2 << endl;
#endif
system("pause");
return 0;
}
const_demo_2(常成员变量,常函数,常对象).cpp
/*************************************************
** 功能 : 常数据成员,常成员函数,常对象
** 作者 : tsingke
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
class circle
{
private:
double R;
const double pi;//常成员变量
static int TotalCount;
public:
circle(double r = 0):pi(3.1415926)
{
this->R = r;
}
//修改半径
double getR() //普通函数
{
cout << "getR()被调用" << endl;
return R;
}
//访问半径
double getR() const //常成员函数,重装函数
{
cout << "getR()const被调用" << endl;
//setR(2);//报错,因为常函数不能访问普通非常函数,只能常对常访问
return R;
}
//访问半径
void setR(double r)
{
R = r;
}
//输出面积
double area()
{
getR();//普通函数可以访问常函数
return pi * R*R;
}
//输出周长
double circumstance()
{
return 2 * pi*R;
}
};
int circle::TotalCount = 0;//定义初始化静态成员变量
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
circle A;//普通的对象
const circle B(3.5);//常对象,带参初始化(务必要初始化)
const circle C;//常对象,采用构函默认值初始化
cout<< "A.getR() = "<< A.getR()<<endl;//普通对象调用对应的非常函数,如果非常函数不存在,就调用常函数
cout<< "B.getR() = " <<B.getR()<<endl;//常对象调用常函数
A.setR(5.4);//正确,普通对象可访问所有类内普通函数
//B.setR(12);//报错,常对象不能访问普通函数,必须访问常成员函数
system("pause");
return 0;
}
static — 静态成员
complex.h
#ifndef COMPLEX_H
#define COMPLEX_H
class complex
{
private:
double x;
double y;
static int count;//私有的静态成员变量
public:
complex(int px,int py);
~complex();
void display();
static int s;//公有的静态成员变量
static void showcount();//
};
//int complex::s=0; //类外初始化,务必注意,如果将类采用多文件编程时,静态成员变量的定义不要放在.h文件中,放在.cpp文件中,否则会引发多重定义问题.
//int complex::count=0;//类外初始化,必注意,如果将类采用多文件编程时,静态成员变量的定义不要放在.h文件中,放在.cpp文件中,否则会引发多重定义问题.
#endif // COMPLEX_H
complex.cpp
#include "complex.h"
#include <iostream>
//初始化静态数据成员
int complex::s=0; //类外初始化,务必注意,如果将类采用多文件编程时,静态成员变量的定义不要放在.h文件中,放在.cpp文件中,否则会引发多重定义问题.
int complex::count=0;
//-------c/c++中的static本质:持久化存储,实现数据共享功能-------------
using namespace std;
//extern int global;
complex::complex(int px, int py):x(px),y(py)
{
cout<<"Constructor is called"<<endl;
count++;
cout<<"cout = "<<count<<endl;
}
complex::~complex()
{
cout<<"destructor is called"<<endl;
count--;
cout<<"cout = "<<count<<endl;
}
void complex::display()
{
cout<<"x = "<<x<<endl;
cout<<"y = "<<y<<endl;
showcount();//普通函数可以直接访问静态函数
}
void complex::showcount()//本质是类外的全局函数
{
cout<<"count = "<<count<<endl;
//this->x=2;//静态成员函数无法访问非静态成员
//display();//会报错,不允许在静态函数访问非静态函数(因为普通函数背后是对象)
}
main.cpp
#include <iostream>
#include "complex.h"
using namespace std;
//int global=10; //可以在整个程序的多个文件内共享的全局变量,只要其他位置将其声明为外部变量即可,exter int global;
static int s_ga=0;//仅在本文件内进行共享的全局变量,外部文件无法访问外联性,external link
void func(int t)
{
static int s_la=0;//static 修饰局部变量,la此时就具有了持久化存储能力,直到程序结束一直存在;初始化工作只在开始执行1次,之后不再初始化
s_la=s_la+t;
cout<<"s_la= "<<s_la<<endl;
}
int main()
{
//-------------------1-----------------------
#if 1
//1. 测试静态全局变量的本质
s_ga=2;
s_ga++;
cout<<"s_ga="<<s_ga<<endl;
#endif
//-------------------2-----------------------
#if 1
//2. 测试静态局部变量的本质
for (int i = 0; i < 10; ++i)
{
func(i);
}
cout << "Hello World!" << endl;
#endif
//------------------3------------------------
#if 1
//3. static 在类中的使用(静态数据成员、静态成员函数)
//静态变量:本质为外部的全局变量,现在将其拉到类内,实现封装
//静态函数:本质为外部的全局函数,专门为访问类内静态变量而设置。
complex ca(2,5);
complex cb(1,4);
//3.1 类直接访问公有静态数据成员
cout<<"complex::s= "<<complex::s<<endl;
//3.1 对象访问公有静态数据成员
cout<<"ca.s = "<<ca.s<<endl;
cout<<"cb.s = "<<cb.s<<endl;
//~~~~
//3.2 类通过静态成员函数访问私有静态数据成员(专门为类服务的)
complex::showcount();
//3.2 对象通过访问静态成员函数访问私有静态数据
ca.showcount();
ca.display();
#endif
//cout<<"complex::count"<<complex::count<<endl;
return 0;
}
第五章:类关系—继承
内容说明:本章研究类与类之间的继承关系,包含三种继承方式、同名冲突、多继承构造函数调用次序、菱形继承、赋值兼容性。
chapt5_class relations/inheritance/README.md
1-inheritance_定义和三种继承理解.cpp
/*************************************************
** 功能 : 类三种继承的定义形式,三种继承关系的深刻理解
** 作者 : tsingke
** 时间 : 2019-11-25 / 21:37
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
class A //作为基类
{
//------------------成员数据------------------
public:
int a_pub;
protected:
int a_pro;
private:
int a_pri;
//------------------成员函数------------------
public:
A(int pub=0, int pro=0, int pri=0) //有参构造
{
cout << "A() is called" << endl;
this->a_pub = pub;
this->a_pro = pro;
this->a_pri = pri;
}
~A()//析构函数
{
cout << "~A() is called" << endl;
getchar();
}
void dispaly()
{
cout << "基类对象成员数据:" << a_pub << " " << a_pro << " " << a_pri<<endl;
}
};
//--------------------研究三种不同的继承方式------------------------
class B:public A //公有继承
{
private:
int bb;
public:
B(int b=2):A(2,2,2)
{
this->bb = b;
cout << "B() is called" << endl;
}
~B()
{
cout << "~B() is called" << endl;
getchar();
}
void display()//探索公有继
{
//基类数据传承探索
a_pub = 200;//a_pub仍为公有数据,子类内可以直接访问
a_pro = 200;//a_pro仍为保护数据,子类内可以直接访问
//a_pri = 200;//报错,基类私有成员在子类不可见
//基类函数传承探索
A::dispaly();
cout << "自身添加数据成员: bb = "<<bb << endl;
}
};
class C: protected A //保护继承
{
private:
int cc;
public:
C(int c=3):A(3,3,3)
{
cout << "C() is called" << endl;
this->cc = c;
}
~C()
{
cout << "~C() is called" << endl;
getchar();
}
void display()//探索保护继承
{
//基类数据传承探索
a_pub = 300;//a_pub变为保护数据,类内可以直接访问
a_pro = 300;//a_pro变为保护数据,类内可以直接访问
//a_pri = 300;//报错,基类私有成员在子类不可见
//基类函数传承探索
A::dispaly();
cout << "自身添加数据成员: cc = " << cc << endl;
}
};
class D : private A //私有继承
{
private:
int dd;
public:
D(int d = 4): A(4, 4, 4)
{
cout << "D() is called" << endl;
this->dd = d;
}
~D()
{
cout << "~D() is called" << endl;
getchar();
}
void display()//探索私有继承
{
//基类数据传承探索
a_pub = 400;//a_pub变为私有数据,子类内可以直接访问
a_pro = 400;//a_pro变为私有数据,子类内可以直接访问
//a_pri = 400;//报错,基类私有成员在子类不可见
//基类函数传承探索
A::dispaly();
cout << "自身添加数据成员: dd = " << dd << endl;
}
};
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
//功能1:通过比较类的大小,证明无论哪种继承方式都会全盘接受基类成员,包括私有的成员
#if 1
cout << "基类A的大小为: " << sizeof(A) << endl;
cout << "--类B的大小为: " << sizeof(B) << endl;
cout << "--类C的大小为: " << sizeof(C) << endl;
cout << "--类D的大小为: " << sizeof(D) << endl;
cout << "---------------------------------" << endl;
#endif
//功能2:构造函数和析构函数的调用
#if 1
A a;
cout << "---------------" << endl;
B b;
cout << "---------------" << endl;
C c;
cout << "---------------" << endl;
D d;
cout << "---------------" << endl;
#endif
//功能3:三种继承的使用(类外访问探索)
#if 0
//------------类B--公有继承--类A---------------
B b;//派生类B的对象
b.a_pub = 200; //正确, 子类内仍然为公有成员,类内外均可访问
//b.a_pro = 200; //错误,子类内仍然为保护成员,类内可直接访问,类外不可以
//b.a_pri = 200; //错误,基类私有成员在子类内外均不可见
//b.dispaly(); //正确,访问的是子类自身的公有成员
//b.A::dispaly();//正确, 子类内函数仍然为公有成员,类内外均可访问
#endif
#if 0
//------------类C--保护继承--类A---------------
C c;//派生类C的对象
//c.a_pub = 300;//错误,变为子类保护成员,无法类外直接访问
//c.a_pro = 300;//错误,变为子类保护成员,无法类外直接访问
//c.a_pri = 300;//错误,基类私有成员在子类内外均不可见
//c.display(); //正确,访问的是子类自身的公有成员
//c.A::dispaly(); //错误,变为子类的保护函数,不可类外访问
#endif
#if 0
//------------类D--私有继承--类A---------------
D d;//派生类D的对象
//d.a_pub = 400; //报错,变为子类的私有成员,无法类外直接访问
//d.a_pro = 400; //报错,变为子类的私有成员,无法类外直接访问
//d.a_pri = 400; //报错,基类私有成员在子类内外均不可见
//d.dispaly(); //报错,变为子类私有成员,无法类外直接访问
//d.A::dispaly(); //错误,继承后变为子类私有函数,无法类外直接访问
#endif
system("pause");
return 0;
}
2-inheritance-父子同名与数据访问方式.cpp
/*************************************************
** 功能 : 类的继承中,父子类间同名冲突问题(单继承)
** 作者 : tsingke
** 时间 : 2019-11-25
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
class base
{
private:
int a;
public:
base(int _a):a(_a)
{
this->a = _a;;
}
~base() {}
int get() { return a; }
};
class derived : public base
{
private:
int a;
public:
derived(int _a) :base(_a*10)
{
this->a = _a;
}
~derived() {}
int get() { return a; }
};
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
base b(10);
derived d(20);
//1.冲突解决: 通过域名解析符来访问被子类遮挡的父类的同名成员
cout<<"d.get()= "<< d.get()<<endl; //只能访问派生类的get函数(掩盖了基类的get函数)
cout<<"d.base::get()= "<<d.base::get()<<endl;//访问父类中的同名函数,通过域名解析的方法
//2.基类指针用法
cout << "------基类指针指向派生类对象----------" << endl;
base *pb;
pb = &d;
cout<<"pb->get() = "<<pb->get()<<endl;//通过基类指针指向派生类对象, 基类指针仅能访问到被派生类继承过去的成员数据或成员函数
//3. 基类引用用法
cout << "------基类引用,引用派生类对象----------" << endl;
base &r = d;
cout <<" r.get() = "<< r.get() << endl;//
system("pause");
return 0;
}
3-inheritance-多继承与基类构函调用次序问题.cpp
/*************************************************
** 功能 : 类的多继承-同名冲突问题/基类构函调用次序问题
** 作者 : tsingke
***************************************************/
#include <iostream>
#include <cstdlib>
#include <windows.h>
using namespace std;
class base1
{
public:
int a;
base1(int _a)
{
cout << "base1() is called" << endl;
this->a = _a;
}
~base1()
{
cout << "~base1() is called" << endl;
getchar();
}
void print()
{
cout << "base1的a = " << a << endl;
}
};
class base2
{
public:
int a;
base2(int _a)
{
cout << "base2() is called" << endl;
this->a = _a;
}
~base2()
{
cout << "~base2() is called" << endl;
getchar();
}
void print()
{
cout << "base2的a = " << a << endl;
}
};
//构造函数调用次序与下面"定义派生类"时各个基类出现的先后顺序有关,与其在文件中定义的顺序无关
class derived : public base2, public base1
{
public:
int a;
public:
derived(int _a):base1(_a * 2),base2(_a * 3)
{
cout << "derived() is called" << endl;
this->a = _a;
}
~derived()
{
cout << "~derived() is called" << endl;
getchar();
}
void print()
{
cout << "derived的a = " << a << endl;
}
};
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
//1. 派生类访问自己的数据
derived d(1);
cout << "d.a = " << d.a << endl;
d.print();//优先访问派生类的函数
cout << "-----------------------" << endl;
//2.派生类对象访问继承自父类的数据成员
cout << "d.base1::a = " << d.base1::a << endl;
cout << "d.base2::a = " << d.base1::a << endl;
cout << "-----------------------" << endl;
//3. 访问基类中的同名函数
d.base1::print();//访问基类1中的同名函数
d.base2::print();//访问基类2中的同名函数
system("pause");
return 0;
}
4-inheritance-菱形继承sofabed.cpp
/*************************************************
** 功能 : 类的多继承:菱形继承解决方案-虚继承
** 作者 : tsingke
** 提示 : 绘制派生类成员关系图,不迷路
***************************************************/
#include <iostream>
using namespace std;
//定义家具类(祖先类)
class Furnitrue
{
public:
void Show()
{
cout <<"m_weight " << m_weight << endl;
cout <<"m_color" << m_color << endl;
}
//一个类如果想要让别人来继承,同时要保证自己数据的封装性,那么可以将其定义为protected类型
protected:
int m_weight;//家具的重量数值(公共属性)
int m_color; //家具的颜色数值(公共属性)
};
//1.定义沙发类
class Sofa : virtual public Furnitrue
{
public:
Sofa(int x=50, int y=100)
{
m_weight = x;
m_color = y;
}
void sit()
{
cout << "Sofa can sit" << endl;
}
};
//2.定义床类
class Bed : virtual public Furnitrue
{
public:
Bed(int x=50, int y=100)
{
m_weight = x;
m_color = y;
}
void sleep()
{
cout << "Bed can sleep" << endl;
}
};
//3. 定义沙发床类
class SofaBed : public Sofa, public Bed
{
public:
SofaBed(int x, int y)
{
m_weight = x;//只有一份
m_color = y;//只有一份
}
};
int main()
{
SofaBed sb(100, 999);
sb.sit();
sb.sleep();
sb.Show();
return 0;
}
5-inheritance-赋值兼容.cpp
#include <iostream>
using namespace std;
//赋值兼容(有亲缘关系的数据才可以赋值,晚辈赋值给长辈)
//1派生类对象可以赋值给基类对象
//2派生类对象可以初始化基类的引用
//3派生类对象的地址可以赋值给指向基类的指针
//定义图形类
class Shape
{
public:
Shape(int x=0, int y=0)
:m_x(x),m_y(y)
{
}
void Draw()
{
cout << "Shape::" << "(" << m_x << "," << m_y << ")" << endl;
}
protected:
int m_x;
int m_y;
};
//定义圆类
class Circle : public Shape
{
public:
Circle(int x=0, int y=0, int r=0)
:Shape(x,y),m_radius(r)
{
}
void Draw()
{
cout << "Circle::" << "(" << m_x << "," << m_y << ")" << "radius" << m_radius << endl;
}
protected:
int m_radius;
};
int main()
{
//1.派生类对象可以赋值给基类对象
//Shape s(1,2);
//s.Draw();
//Circle c(3,4,5);
//c.Draw();
//
//s = c;
//s.Draw();
//2.派生类对象可以初始化基类的引用
// Circle c(3,4,5);
// Shape & rs = c;
// rs.Draw();
//3.派生类对象的地址可以赋值给指向基类的指针
//Circle c(3,4,5);
//Shape *ps = &c;
//ps->Draw();
//int a = 10;
//int *pi = &a;
//char *pc = &a; //这样是不安全的
//
//char ch = 'a';
//int *pi = &ch;//这样是不安全的
return 0;
}
第六章:多态性
1-静态多态性
内容说明:静态多态性通过函数重载实现,包含普通函数的重载和运算符重载(成员函数法、友元函数法)。
complex.h
#ifndef COMPLEX_H
#define COMPLEX_H
#include <iostream>
using namespace std;
class complex
{
private:
double real;
double imag;
public:
//===================静态多态: 函数重载========================
complex();
complex(double r, double i);//构造函数
complex(const complex &r);
~complex();
void print();
void print()const;
//===============静态多态: 运算符重载1-成员函数法===============
//a.重载加法运算符+(双目运算符)
complex operator+(const complex &other);
//b.重载赋值运算符=(双目运算符)-类内重载
complex operator=(const complex &other);
//c.重载前++运算符(单目运算符)-类内重载,类外重载均可
complex operator++();
//d.重载后++运算符(单目运算符)-类内重载
complex operator++(int);
//e.重载函数调用运算符()运算符(单目运算符)-类内重载
double operator()();
//===============静态多态: 运算符重载2-友元函数法===============
//-重载输出运算符<< : 双目运算符,格式"cout<<" 左侧是一个输出流对象cout"
friend ostream& operator<<(ostream &out, complex &t);
};
#endif // COMPLEX_H
complex.cpp
#include "complex.h"
//-----------------------成员函数-------------------------
complex::complex()
{
}
complex::complex(double r, double i)
{
this->real =r;
this->imag =i;
}
complex::complex(const complex &r)
{
this->real =r.real;
this->imag = r.imag;
}
complex::~complex()
{
}
void complex::print() const
{
}
complex complex::operator+(const complex &other)
{
complex temp;
temp.real = this->real + other.real;
temp.imag = this->imag + other.imag;
return temp;
}
//赋值运算符=
complex complex::operator=(const complex &other)
{
this->real = other.real;
this->imag = other.imag;
}
//前++
complex complex::operator++()
{
++this->real;
++this->imag;
return *this;
}
//后++
complex complex::operator++(int)
{
complex temp;//
temp.real = this->real++;
temp.imag=this->imag++;
return temp;
}
//函数调用符
double complex::operator()()
{
double sum = this->real * this->real + this->imag *this->imag;
return sum;
}
//-----------------------友元函数-------------------------
ostream & operator<<(ostream &out, complex &t)
{
out<<t.real<<"+" <<t.imag<<"i"<<endl;
}
main.cpp
/*-------------------------------------
* 功能: 类的静态多态性(函数重载+运算符重载)
* 作者: tsingke
-------------------------------------*/
//静态多态: 函数重载(同名不同参) + 运算符重载(4种)
#include <iostream>
using namespace std;
#include "complex.h"
//--------------主函数---------------
int main()
{
//定义复数类的对象
complex a(6,6);
complex b(8,8);
complex c,d,e;
//1. 重载输出运算符<<, 输出大对象 (双目运算符)
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
cout<<"c="<<c<<endl;
//2. 重载加法运算符+ (双目运算符),
c = a + b;//a.operator+(b);
cout<<c;
//3. 重载赋值运算符= (如果对象不涉及堆内存资源,不建议重载赋值运算符,使用系统提供的就可以)
c = a;
cout<<c<<endl;
//4. 重载函数调用运算符() (多目运算符)
cout<<a()<<endl;//输出距离real^2 +imag^2;
//5.1 重载后++, 对象a++(后加加)-(单目运算符)
d=a++;
cout<<"d=a++; d = "<<d<<endl;
//5.2 重载前++,对象++b(前加加)-(单目运算符)
e=++b;
cout<<"e=++b; e = "<<e<<endl;
return 0;
}
2-动态多态性
内容说明:动态多态性通过虚函数实现,包含赋值兼容性、虚函数原理、虚析构函数、纯虚函数与抽象类,以及游戏实战案例。
1-预备工作-赋值兼容性.cpp
/*************************************************
** 功能 : 动态多态性--指哪打哪如何实现
** 作者 : tsingke
***************************************************/
#include <iostream>
#include <cstdlib>
using namespace std;
class base
{
private:
int a;
int b;
int c;
public:
base()
{
cout<<"base() is called"<<endl;
}
void display()
{
cout<<"base-display() is called "<<endl;
}
};
class derive: public base
{
private:
int x,y,z;
public:
derive()
{
cout<<"derive() is called"<<endl;
}
};
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
base father;
derive son;
//---------探索赋值兼容性:3种类型---------
father = son;//赋值兼容性1
//son = father;//错误, 父类对象不能赋值给派生类对象
base *p = &son;//赋值兼容性2
base &r = son;//赋值兼容性3
father.display();//调用父类函数
p->display(); //调用父类内的函数
r.display(); //调用父类内的函数
/*
* 赋值兼容性存在的问题:无法通过父类指针访问到子类新添加的同名函数
* 解决方法:在基类内设置同名函数为虚函数,即可实现"指哪打哪"的效果
**/
return 0;
}
2-动态多态性-虚函数-指哪打哪.cpp
/*************************************************
** 功能 : 动态多态性--只要公有继承,长相相同,就能指哪打哪
** 作者 : tsingke
***************************************************/
#include <iostream>
#include <cstdlib>
using namespace std;
class base
{
private:
int a;
int b;
int c;
public:
base()
{
cout<<"base() is called"<<endl;
}
virtual void display()
{
cout<<"base-display() is called "<<endl;
}
};
class derive: public base
{
private:
int x,y,z;
public:
derive()
{
cout<<"derive() is called"<<endl;
}
void display()//由于父类同名函数display()为虚函数,因此,子类同名函数自动变为虚函数
{
cout<<"derive-display() is called "<<endl;
}
};
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
base father;
derive son;
//--------虚函数实现动态多态性---------
father = son;//赋值兼容性1
//son = father;//错误, 父类对象不能赋值给派生类对象
base *p = &son;//赋值兼容性2
base &r = son;//赋值兼容性3
father.display();//调用父类函数
p->display(); //调用子类内的函数(p指向子类对象,调用子类函数)
r.display(); //调用子类内的函数(r引用子类对象,调用子类函数)
/*
* 赋值兼容性存在的问题:无法通过父类指针访问到子类新添加的同名函数
* 解决方法:在基类内设置同名函数为虚函数,即可实现"指哪打哪"的效果
**/
return 0;
}
3-动态多态性-虚函数原理挖掘.cpp
/*************************************************
** 功能 : 动态多态性--虚函数实现原理
** 作者 : tsingke
***************************************************/
#include <iostream>
#include <cstdlib>
using namespace std;
class base
{
private:
int a;
public:
base()
{
cout << "base() is called" << endl;
}
virtual void display()
{
cout << "base-display() is called " << endl;
}
};
class derive : public base
{
private:
int x;
public:
derive()
{
cout << "derive() is called" << endl;
}
void display()//由于父类同名函数display()为虚函数,因此,子类同名函数自动变为虚函数
{
cout << "derive-display() is called " << endl;
}
};
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
base father;
derive son;
//-----虚函数通过设置虚函数表实现-----
cout << "---------------------" << endl;
cout << "base 类大小为: " << sizeof(base) << endl;
cout << "derive类大小为: " << sizeof(derive) << endl;
cout << "---------------------" << endl;
//--------虚函数实现动态多态性---------
father = son;//赋值兼容性1
//son = father;//错误, 父类对象不能赋值给派生类对象
base *p = &son;//赋值兼容性2
base &r = son;//赋值兼容性3
father.display();//调用父类函数
p->display(); //调用子类内的函数(p指向子类对象,调用子类函数)
r.display(); //调用子类内的函数(r引用子类对象,调用子类函数)
/*
* 赋值兼容性存在的问题:无法通过父类指针访问到子类新添加的同名函数
* 解决方法:在基类内设置同名函数为虚函数,即可实现"指哪打哪"的效果
**/
getchar();
return 0;
}
4-动态多态性-虚析构函数.cpp
/*************************************************
** 功能 : 动态多态性--虚析构函数(一虚全虚)
** 作者 : tsingke
***************************************************/
#include <iostream>
#include <cstdlib>
using namespace std;
//--------------------父类----------------------------
class base
{
private:
int a;
public:
base()
{
cout << "base() is called" << endl;
}
//~base(){}//
virtual ~base()
{
cout << "~base() is called" << endl;
}
virtual void print()
{
cout << "base-print() is called" << endl;
}
};
//--------------------子类----------------------------
class derive : public base
{
private:
int *id;
public:
derive()
{
id = new int[10];
cout << "derive() is called" << endl;
}
~derive()//如果基类析构函数为虚函数,则子类的析构函数全都自动变为虚函数
{
cout << "~derive() is called" << endl;
if (id!=NULL)
{
delete[] id;
}
}
virtual void print() //公有继承,长相相同
{
cout << "derive-print() is called" << endl;
}
};
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
base *p = new derive; //通过基类指针创建无名对象
p->print(); // 通过虚函数实现"指哪打哪"的目的
delete p; //通过基类指针释放无名对象
return 0;
}
5-动态多态性-纯虚函数.cpp
/*************************************************
** 功能 : 纯虚函数与抽象类
** 作者 : 张庆科
** 时间 : 2019-12-9
***************************************************/
#include <iostream>
#include <cstdlib>
#include <cmath> //不要落掉,调用其sqrt()函数
#include <windows.h>
using namespace std;
//----------------抽象类: 图形类-------------------
class shape
{
public:
virtual double circumstance() = 0;
virtual double area() = 0; //含有纯虚函数的类就是抽象类
};
//----------------具体类:正方形类-------------------
class squre:public shape
{
private:
double a;
public:
squre(int _a) :a(_a)
{
cout << "生成正方形对象, 边长 = " << a << endl;
}
~squre() {}
double circumstance()//基类同名为虚函数,子类相同函数自动变为虚函数(公有继承,长相相同)
{
return 4 * a;
}
double area() //基类同名为虚函数,子类相同函数自动变为虚函数(公有继承,长相相同)
{
return a * a;
}
};
//----------------具体类:三角形类-------------------
class triangle:public shape
{
private:
double a, b, c;
public:
triangle(double _a, double _b, double _c) :a(_a), b(_b), c(_c)
{
if ((a+b<=c) || (a+c<=b) || (b+c <=a))
{
cout << "无法构成三角形,请重新输入三条边:" << endl;
cin >> a;
cin >> b;
cin >> c;
}
cout << "生成三角形对象, 边长 = " << a <<" "<< b << " " << c<<endl;
}
~triangle() {}
double circumstance() //基类同名为虚函数,子类相同函数自动变为虚函数(公有继承,长相相同)
{
return a + b + c;
}
double area() //基类同名为虚函数,子类相同函数自动变为虚函数(公有继承,长相相同)
{
double p = 0.5 * circumstance();
return sqrt(p*(p - a)*(p - b)*(p - c));
}
};
//全局函数,输出某个图形的周长和面积
void display(shape *p)
{
cout << "周长为: " << p->circumstance() << endl;//多态语句(指哪打哪)
cout << "面积为: " << p->area() << endl; //多态语句(指哪打哪)
cout << "------------------------------" << endl;
}
/*----------------------------------*
Main Function
*-----------------------------------*/
int main()
{
squre squ(10); //正方形类对象
triangle tri(3, 4, 5); //三角形类对象
//------------1. 抽象类的特性探索----------
//shape sha; // 错误, 不可以生成抽象类的对象
cout << "sizeof(shape) = " << sizeof(shape) << endl;//可以计算抽象类大小
shape *p; // 正确, 可以建立抽象类的指针变量
shape &r = squ;//正确, 可以建立抽象类的对象引用,引用的是派生类对象
//-----------2. 动态多态特性探索-----------
cout << endl;
cout << "正方形的周长和面积:"<<endl;
display(&squ);//输出正方形的周长和面积, 指哪打哪
cout << "三角形周长和面积:"<<endl;
display(&tri);//输出三角形的周长和面积, 指哪打哪
system("pause");
return 0;
}
游戏王者争霸-虚函数与动态多态.cpp
/*************************************************
** 功能 : 动态多态实践应用: 王者争霸游戏模拟
** 作者 : tsingke
/**************************************************/
//动态多态:借助虚函数实现
//动态多态条件: 公有继承(public), 原型相同(基类与子类某个函数原型相同)
//实现的结果 :指哪打哪
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int killDragon = 0;
int killLion = 0;
int killTiger = 0;
const int MaxDragon = 5;
const int MaxLion = 20;
const int MaxTiger = 30;
const int iter = 100;
//-------------------基类:所有游戏角色的基类------------------------
class Canimal
{
protected:
double lifeValue; // 生命力,自身的寿命
double power; // 攻击力,对其他动物
public:
virtual void Attack(Canimal *other) {}; //虚函数: 自己主动攻击别人
virtual void Fightback(Canimal *own) {};//虚函数: 攻击别人时被别人反击自己
virtual void Hurted(int power) {}; //虚函数: 自己被别人主动攻击
};
//-------------------具体类: dragon龙类------------------------
class Cdragon : public Canimal
{
public:
Cdragon(double _value = 100, double _power = 50)
{
this->lifeValue = _value;
this->power = _power;
}
//自己被别人攻击
void Hurted(int power)
{
this->lifeValue -= power;
if (lifeValue <= 0)
{
cout << "龙被打死了 ";
killDragon++;
}
}
//被反击:攻击别人时,被别人反击
void Fightback(Canimal *p)
{
p->Hurted(0.5*power);
}
//主动攻击: 自己攻击别人,使别人受伤,自己也受到一些对方的反击伤害
void Attack(Canimal *other)
{
other->Hurted(power); //攻击别人,使别人受伤
other->Fightback(this);//被别人反击,自己也受伤
}
};
//-------------------具体类: CLion 狮子类------------------------
class Clion : public Canimal
{
public:
Clion(double _value = 100, double _power = 30)
{
this->lifeValue = _value;
this->power = _power;
}
//自己被别人攻击
void Hurted(int power)
{
this->lifeValue -= power;
if (lifeValue <= 0)
{
cout << "狮子被打死了 ";
killLion++;
}
}
//被反击:攻击别人时,被别人反击
void Fightback(Canimal *p)
{
p->Hurted(0.5*power);
}
//主动攻击: 自己攻击别人,使别人受伤,自己也受到一些对方的反击伤害
void Attack(Canimal *other)
{
other->Hurted(power); //攻击别人,使别人受伤
other->Fightback(this);//被别人反击,自己也受伤
}
};
//-------------------具体类: CTiger 老虎类------------------------
class Ctiger : public Canimal
{
public:
Ctiger(double _value = 100, double _power = 20)
{
this->lifeValue = _value;
this->power = _power;
}
//自己被别人攻击
void Hurted(int power)
{
this->lifeValue -= power;
if (lifeValue <= 0)
{
cout << "老虎被打死了 ";
killTiger++;
}
}
//被反击:攻击别人时,被别人反击
void Fightback(Canimal *p)
{
p->Hurted(0.5*power);
}
//主动攻击: 自己攻击别人,使别人受伤,自己也受到一些对方的反击伤害
void Attack(Canimal *other)
{
other->Hurted(power); //攻击别人,使别人受伤
other->Fightback(this);//被别人反击,自己也受伤
}
};
//=============================主函数================================
int main()
{
srand((unsigned)time(NULL));
//1. 初始化一群动物对象
Cdragon dragon[MaxDragon];//龙类对象数组
Clion lion[MaxLion]; //狮子类对象数组
Ctiger tiger[MaxTiger]; //老虎类对象数组
//2. 动物开始随机厮杀
cout << "王者争霸游戏已开启,请按任意键开始>>>>>" << endl;
getchar();
for (int i = 0; i < iter; ++i)
{
cout << "开始第" << i + 1 << "轮厮杀: ";
switch (rand() % 2)
{
case 0: //龙攻击狮子
{
//随机选择一个龙和一头狮子
int id1 = rand() % MaxDragon;
int id2 = rand() % MaxLion;
dragon[id1].Attack(&lion[id2]);
}
break;
case 1: //狮子攻击老虎
{
//随机选择一个狮子和一只老虎
int id1 = rand() % MaxLion;
int id2 = rand() % MaxTiger;
lion[id1].Attack(&tiger[id2]);
} break;
case 2: // 老虎攻击龙
{
//随机选择一个老虎和一条龙
int id1 = rand() % MaxTiger;
int id2 = rand() % MaxDragon;
tiger[id1].Attack(&dragon[id2]);
} break;
}//switch
cout << "kill掉" << (killDragon + killLion + killTiger) << "个怪物" << endl;
}//for
cout << "-------------------------" << endl;
cout << "游戏结束!" << endl<<endl;
cout << "共kill掉" << killDragon << "条龙" << endl;
cout << "共kill掉" << killLion << "头狮" << endl;
cout << "共kill掉" << killTiger << "只虎" << endl;
system("pause");
return 0;
}