0. 温习
0.1 虚继承
当咱们应用多继承的时候,子类的多个父类有同名成员,拜访的时候,会呈现二义性
class CA
{
public:
int m_a;
};
class CB
{
public:
int m_a;
};
class CTest:public CA,public CB
{
};
int main()
{
CTest obj;
obj.m_a = 10;
return 0;
}
解决形式 1:能够应用类的作用域拜访具体某一个父类的成员
解决形式 2:给 CA 和 CB 形象出一个独特的父类,而后应用虚继承
class CBase
{
public:
int m_a;
};
class CA:virtual public CBase
{
public:
//int m_a;
};
class CB:virtual public CBase
{
public:
//int m_a;
};
class CTest :public CA, public CB
{
};
int main()
{
CTest obj;
obj.m_a = 20;
obj.CA::m_a = 10;
obj.CB::m_a = 20;
return 0;
}
如果类 B 虚继承自类 A,此时类 A 就是 虚基类
0.2 虚函数与多态
当咱们应用父类指针指向子类对象,调用虚函数,优先调用子类的虚函数。子类如果没有实现这个虚函数,就调用父类的。
虚函数是多态机制,属于动静联编。
virtual void fun() =0 ; 这个叫做纯虚函数。只是提供了接口,没有提供具体实现,实现由子类来实现。
抽象类:蕴含纯虚函数的类,也叫做抽象类。如果子类没有实现父类中的纯虚函数,子类也是抽象类。
抽象类的特点:不能定义对象
class Tuxing
{
public:
virtual int ClacArea() = 0;};
class Sanjiaoxing:public Tuxing
{
public:
int ClacArea()
{return m_nBottom * m_nHeight / 2;}
private:
int m_nBottom;
int m_nHeight;
};
class CZhengfangxing :public Tuxing
{int ClacArea()
{
//..
return m_nLenth * m_nLenth;
}
private:
int m_nLenth;
};
class CCircle:public Tuxing
{
};
int main()
{
CCircle obj;
CZhengfangxing obj2;
return 0;
}
重载,重定义,虚函数定义
重载:雷同作用域 函数名雷同 参数不同 调用的时候依据传参的不同,编译器主动调用相应的函数
重定义:继承关系中 函数名雷同 参数能够雷同也能够不雷同 子类对象默认调用本人的
虚函数:继承关系中 函数名雷同 参数雷同 须要加上 virtual 应用特点:父类指针指向子类对象,调用虚函数,优先调用子类的
0.3 模板
0.3.1 函数模板
template <typename M,typename N,typename L>
void Fun(M a, N b, L c, int nLenth)
{
}
int main()
{Fun(1, 2.5, 'c', 100);
return 0;
}
模板的特化:
不能应用通用算法解决一些数据类型,能够为其独自实现算法。这个叫做特化
template <>
void Fun(int a, int b, double c, int nLenth)
{}
0.3.2 类模板
咱们应用 C 语言的数组,它的长度只能是一个常量,不能动静扩大。应用起来不太不便。对于一些惯例的数组操作,都须要本人去实现。没有面向对象的反对,咱们实现一个动静数组,反对以下性能:
1. 反对动静增长
2. 反对任意数据类型
3. 反对惯例的数组操作
(增 删 改 查)
#pragma once
// 先实现一个存储 int 类型的数组,元素如果最多 100 个
template<typename T>
class CMyArr
{
public:
CMyArr(int nMax = 3);
// 减少一个数据
bool Insert(T nData, int nLoc);
// 删除一个数据
bool DeleteEle(int nLoc);
bool ModifyByLoc(T nData, int nLoc);
bool GetEleByLoc(int nLoc, T& Ele);
// 获取以后元素个数
int GetLenth();
bool sort();
private:
T* m_buf;
int m_nLenth;
int m_nMax;
};
template<typename T>
CMyArr<T>::CMyArr(int nMax) :m_buf{0}, m_nLenth(0), m_nMax(nMax)
{m_buf = new T[nMax]{0};
}
// 减少一个数据
template<typename T>
bool CMyArr<T>::Insert(T nData, int nLoc)
{
//1. 检测传入的地位,是否正确
if (nLoc<0 || nLoc>m_nLenth)
{return false;}
//2. 是否缓冲区曾经满了
if (m_nLenth == m_nMax)
{
// 如果缓冲区满了,那么就能够申请更大的空间,而后去存储
T* pTemp = new T[m_nMax * 2]{0};
// 将老缓冲区中的数据拷贝到新申请的缓冲区
for (int i = 0; i < m_nMax; i++)
{pTemp[i] = m_buf[i];
}
// 开释原来的缓冲区
delete[]m_buf;
m_buf = pTemp;
m_nMax *= 2;
}
//3. 增加数据的地位,在结尾,间接增加
if (m_nLenth == nLoc)
{m_buf[nLoc] = nData;
m_nLenth++;
return true;
}
//4. 增加数据的地位,在两头,须要挪动数据,再增加
for (int i = m_nLenth - 1; i >= nLoc; i--)
{m_buf[i + 1] = m_buf[i];
}
// 曾经挪动完数据了,增加数据
m_buf[nLoc] = nData;
m_nLenth++;
return true;
}
// 删除一个数据
template<typename T>
bool CMyArr<T>::DeleteEle(int nLoc)
{
//1. 检测地位是否正确
if (nLoc < 0 || nLoc >= m_nLenth)
{return false;}
//2. 删除的是结尾,不须要挪动
if (nLoc == m_nLenth - 1)
{
m_nLenth--;
return true;
}
//3. 删除的是两头,就须要挪动
for (int i = nLoc; i < m_nLenth - 1; i++)
{m_buf[i] = m_buf[i + 1];
}
m_nLenth--;
return true;
}
template<typename T>
bool CMyArr<T>::ModifyByLoc(T nData, int nLoc)
{
//1. 检测地位是否正确
if (nLoc < 0 || nLoc >= m_nLenth)
{return false;}
//2. 地位没有问题,间接赋值
m_buf[nLoc] = nData;
return true;
}
template<typename T>
bool CMyArr<T>::GetEleByLoc(int nLoc, T& Ele)
{
//1. 检测地位是否正确
if (nLoc < 0 || nLoc >= m_nLenth)
{return false;}
//2. 地位没有问题,间接赋值
Ele = m_buf[nLoc];
return true;
}
// 获取以后元素个数
template<typename T>
int CMyArr<T>::GetLenth()
{return m_nLenth;}
template<typename T>
bool CMyArr<T>::sort()
{for (int j = 1; j < m_nLenth; j++)
{for (int i = 0; i < m_nLenth - j; i++)
{if (m_buf[i] > m_buf[i + 1])
{T nTemp = m_buf[i];
m_buf[i] = m_buf[i + 1];
m_buf[i + 1] = nTemp;
}
}
}
return true;
}
具体的应用:
#include <iostream>
#include "MyArr.h"
int main()
{
CMyArr<int> obj;
obj.Insert(10, 0);
obj.Insert(20, 0);
obj.Insert(30, 0);
obj.Insert(100, 1);
obj.Insert(200, 2);
obj.DeleteEle(1);
obj.ModifyByLoc(500, 1);
obj.sort();
for (int i = 0; i < obj.GetLenth(); i++)
{
int nEle = 0;
obj.GetEleByLoc(i, nEle);
std::cout << nEle << " ";
}
CMyArr<char> obj2;
obj2.Insert('a', 0);
obj2.Insert('b', 1);
obj2.Insert('c', 0);
obj2.Insert('d', 1);
obj2.Insert('e', 2);
obj2.Insert('f', 1);
for (int i = 0; i < obj2.GetLenth(); i++)
{
char nEle = 0;
obj2.GetEleByLoc(i, nEle);
std::cout << nEle << " ";
}
obj2.sort();
std::cout << std::endl;
for (int i = 0; i < obj2.GetLenth(); i++)
{
char nEle = 0;
obj2.GetEleByLoc(i, nEle);
std::cout << nEle << " ";
}
return 0;
}
STL -vector
1.1 vertor 的根本应用
#include <iostream>
#include <vector>
#include <algorithm>
using std::vector;
int main()
{
vector<int> obj;
//1. 减少
//push_back 在结尾增加
//insert 在两头增加
obj.push_back(1);
obj.push_back(2);
obj.push_back(3);
obj.push_back(4);
obj.push_back(5);
obj.push_back(6);
//vector 中应用迭代器来标识地位
// 咱们能够暂且认为迭代器是一个指针
// 能够有 + - * 的操作
// 获取起始地位的迭代器
vector<int>::iterator it1 = obj.begin();
obj.insert(it1+2, 100);
//2. 删除
//pop_back 删除结尾
//erase 删除两头
//clear 全副删掉
obj.pop_back();
vector<int>::iterator it2 = obj.begin();
obj.erase(it2+3);
//3. 查问
// 反对下标运算
//size 获取元素个数
std::cout << obj[2];
std::cout << obj.size();
//4. 批改
obj[2] = 10;
std::cout << std::endl;
//5. 遍历
// 第一种遍历形式
for (int i = 0; i < obj.size(); i++)
{std::cout << obj[i]<<" ";
}
std::cout << std::endl;
// 第二种遍历形式
//obj.end()是结尾的迭代器,是最初一个元素的前面
vector<int>::iterator it3 = obj.begin();
for (; it3 != obj.end(); it3++)
{std::cout << *it3 << " ";}
std::cout << std::endl;
//6. 排序
std::sort(obj.begin(), obj.end());
for (int i = 0; i < obj.size(); i++)
{std::cout << obj[i] << " ";
}
std::cout << std::endl;
return 0;
}
1.2 应用 vector 实现一个密码本
#include <iostream>
#include <vector>
using std::vector;
class CPassWordInfo
{
public:
CPassWordInfo(const char* szWeb = nullptr,
const char* szUserName = nullptr,
const char* szPwd=nullptr)
{strcpy_s(m_szWeb, 20, szWeb);
strcpy_s(m_szUserName, 20, szUserName);
strcpy_s(m_szPwd, 20, szPwd);
}
char* GetWeb()
{return m_szWeb;}
char* GetUserName()
{return m_szUserName;}
char* GetPwd()
{return m_szPwd;}
void SetWeb(const char* szWeb = nullptr)
{strcpy_s(m_szWeb, 20, szWeb);
}
void SetUserName(const char* szUserName)
{strcpy_s(m_szUserName, 20, szUserName);
}
void SetPwd(const char* szPwd = nullptr)
{strcpy_s(m_szPwd, 20, szPwd);
}
bool Veryrify()
{ }
private:
char m_szWeb[20];
char m_szUserName[20];
char m_szPwd[20];
};
vector<CPassWordInfo> g_PwdBook;
int main()
{
//1. 用户输出要进行的操作
int nSelect = 0;
while (true)
{system("cls");
std::cout << "减少" << std::endl;
std::cout << "删除" << std::endl;
std::cout << "查问所有" << std::endl;
std::cout << "批改" << std::endl;
std::cout << "输出你的抉择(1~4):" << std::endl;
std::cin >> nSelect;
switch (nSelect)
{
case 1:// 减少
{char szWebSite[20] = {0};
char szUserName[20] = {0};
char szPwd[20] = {0};
//1. 输出站点的信息
std::cout << "站点:" << std::endl;
std::cin >> szWebSite;
std::cout << "账号:" << std::endl;
std::cin >> szUserName;
std::cout << "明码:" << std::endl;
std::cin >> szPwd;
//2. 构建一个对象,存储到 vector
CPassWordInfo obj(szWebSite, szUserName, szPwd);
g_PwdBook.push_back(obj);
break;
}
case 2:// 删除
{
int nDelete = 0;
std::cout << "请输出你要删除的序号:" << std::endl;
std::cin >> nDelete;
// 删除的时候,须要传递迭代器
vector<CPassWordInfo>::iterator it = g_PwdBook.begin();
g_PwdBook.erase(it+nDelete);
break;
}
case 3:// 查问所有
{vector<CPassWordInfo>::iterator it = g_PwdBook.begin();
for (; it != g_PwdBook.end(); it++)
{std::cout << "站点:"<<(*it).GetWeb()<<" ";
std::cout << "用户名:" << (*it).GetUserName()<<" ";
std::cout << "明码:" << (*it).GetPwd()<<std::endl;}
break;
}
case 4:
{
int nModify = 0;
//1. 输出要批改的地位
std::cout << "要批改几号:" ;
std::cin >> nModify;
//2. 输出具体数据
char szWebSite[20] = {0};
char szUserName[20] = {0};
char szPwd[20] = {0};
//3. 输出站点的信息
std::cout << "站点:" << std::endl;
std::cin >> szWebSite;
std::cout << "账号:" << std::endl;
std::cin >> szUserName;
std::cout << "明码:" << std::endl;
std::cin >> szPwd;
//4. 进行批改
g_PwdBook[nModify].SetWeb(szWebSite);
g_PwdBook[nModify].SetUserName(szUserName);
g_PwdBook[nModify].SetPwd(szPwd);
//5. 校验明码
g_PwdBook[nModify].Veryrify();}
default:
break;
}
system("pause");
}
}