6、数据抽象
阅读本节你将掌握的知识点
1、数据抽象:只向外界看到我们想给他们看到的。
只管调用不管内部实现机制。
比如:cout<<“hello c++”<<endl;
2、访问标签强制抽象
C++中使用标签来顶一个类的抽象接口,一个类可以包含0个或者多个访问标签
1)使用公共标签定义的成员都可以访问该程序的所有部分,一个类型的数据抽象视图,由他的公共成员定义的。
2)使用私有标签定义的成员无法访问到使用类的代码,私有备份对使用类型的代码隐藏了实现细节。
特点:访问标签的出现没有频率的限制,每个访问标签制定了紧随其后的成员定义的访问级别,指定访问级别会一直有效,直到遇到下一个访问标签或者遇到类主体的关闭右括号为止。
3、数据抽象的好处
两个重要优势:
1)类内的成员受到了保护,不会因为无意的用户级错误导致对象状态受损。
2)类实现可能随着时间的推移而发生变化,以便应对不断变化的需求,或者应对那些要求不改变用户级代码的错误报告。
4、设计策略
抽象把代码分离为接口和实现,在设计组件的时候,必需保持接口独立于实现,这样如果改变底层实现,接口也将保持不变。
在这种情况下,不管任何程序使用接口,接口都不会收到影响,主需要将最新的实现重新编译。
//示例:把数字实现相加,并且返回总和,addNum和getValue都是公有接口,用户需要知道他们,私有成员total不需要了解,但是是必需的。
#include<iostream>
using namespace std;
class Adder{
private:
//对外隐藏的数据
int total;
public:
//构造函数
Adder(int i = 0)
{
total = i;
}
//对外的接口
void addNum(int number)
{
total +=number;
}
//对外的接口
int getTotal()
{
return total;
}
};
int main(){
Adder a;
a.addNum(10);
a.addNum(20);
a.addNum(30);
cout<<"Total "<<a.getTotal()<<endl;
return 0;
}
7、数据封装
阅读本节你将掌握的知识点
1、C++程序的基本要素:
程序语句(代码)
程序数据
2、封装是面向对象编程中把数据和操作数据的函数绑定在一起的一个概念,可以避免受到外界的干扰和误用,从而确保了安全。
数据封装引申出一个重要的概念,数据隐藏。
3、数据封装是把数据和操作函数捆绑在一起的机制,数据抽象是一种仅向用户暴露接口而把具体实现细节隐藏的机制。
设计策略:
设置类的成员是私有的,保证良好的封装性,也应用在数据成员上,适用于所有的成员,包括虚函数。
//示例:
#include<iostream>
using namespace std;
class Adder{
private:
//对外隐藏的数据
int total;
public:
//构造函数
Adder(int i = 0)
{
total = i;
}
//对外的接口
void addNum(int number)
{
total +=number;
}
//对外的接口
int getTotal()
{
return total;
}
};
int main(){
Adder a;
a.addNum(10);
a.addNum(20);
a.addNum(30);
cout<<"Total "<<a.getTotal()<<endl;
return 0;
}
8、接口
阅读本节你将掌握的知识点
1、接口定义:描述了 类的行为和功能,而不需要完成类的特定的实现。
C++接口是使用抽象类来实现的,抽象类和数据抽象互相不混淆,数据抽象是把一个实现细节与相关的数据分离开的概念。
2、抽象类:如果类中的至少有一个函数被声明为纯虚函数,那么这个类就是抽象类。纯虚函数 virtual double getvolume() = 0;
抽象类的设计目的是为了给其他类提供一个可以继承的适当的基类。抽象类不能被用于实例化对象,只能作为接口使用。
3、如果基类的一个子类需要被实例化,则必须实现每个虚函数,意味着C++支持使用ABC声明接口,如果没有派生类中重写纯虚函数,
就尝试实例化对象,会导致编译错误。
设计策略:
面向对象的系统可能会使用一个抽象的基类,为所有的外部应用程序提供一个适当的、通过的、标准化的接口。
然后,派生类通过继承抽象基类,就把所有类似的操作都继承下来了的外部应用程序提供的功能在抽象基类中以纯虚函数的形式存在的,这些纯虚函数在相应的派生类中被实现。
//示例:一个抽象类如何定义一个接口getArea(),两个派生类如何通过不同的计算方式计算面积来实现相同的函数;
#include<iostream>
using namespace std;
class Shape{
public:
//提供接口框架的纯虚函数
virtual int getArea() = 0;
void setWidth(int wid){
width = wid;
}
void setHeight(int hei){
height = hei;
}
protected:
int height;
int width;
};
class Rectangle:public Shape{
public:
int getArea(){
return (width*height);
}
};
class Triangle:public Shape{
public:
int getArea(){
return (width*height)/2;
}
};
int main(){
Rectangle Rect;
Triangle Tri;
Rect.setWidth(5);
Rect.setHeight(7);
//输出对象的面积
cout<<"Total Rectangle area : "<<Rect.getArea()<<endl;
Tri.setWidth(5);
Tri.setHeight(7);
//输出对象的面积
cout<<"Total Tritangle area : "<<Tri.getArea()<<endl;
return 0;
}
9、异常处理
阅读本节你将掌握的知识点
- throw:当问题出现的时候,程序会抛出一个异常,这是通过使用throw关键字来完成的
- catch:用于捕获异常
- try:代码标识将被激活成特定的异常,后面跟着一个或者多个catch块。
#include<iostream>
using namespace std;
double divison(int a,int b){
if (b == 0){
throw "Division by zero condition";
}
return (a/b);
}
int main()
{
int x = 50;
int y = 0;
double z= 0;
try
{
z = divison(x,y);
}
catch(const char *msg)
{
cerr << "Error: " << msg << endl;
}
return 0;
}
捕获异常
#include<iostream>
using namespace std;
double divison(int a,int b){
if (b == 0){
throw "Division by zero condition";
}
return (a/b);
}
struct MyException:exception
{
const char *what() const throw()
{
return "C++ Exception";
}
};
int main()
{
try
{
throw MyException();
}
catch(MyException& e)
{
std::cout<<"NyException caught"<<std::endl;
std::cout<<e.what()<<std::endl;
}catch(std::exception& e){
//其他错误
}
}
10、模板
阅读本节你将掌握的知识点
-
模板是泛型编程的基础,
泛型编程是以一种独立于任何特定类型的方式编写代码。- 每个容器都有一个单一的定义,比如向量,可以定义不同类型的向量。
vector<int> vector<string>
示例
#include <iostream>
#include<vector>
#include<cstdlib>
#include<stdexcept>
#include <string>
using namespace std;
template <typename T>
inline T MAX(T const &a,T const &b)
{
return a<b?b:a;
}
//类模板
template <typename T>
class Stack{
private:
vector<T> elems; //元素
public:
void push(T const&);//入栈
void pop(); //出栈
T top() const; //返回栈顶元素
bool empty() const{//如果为空返回真
return elems.empty();
}
};
template <typename T>
void Stack<T>::push(T const& elem)
{
//追加传入元素副本
elems.push_back(elem);
}
template <typename T>
void Stack<T>::pop()
{
if (elems.empty()){
throw out_of_range("Stack<>::pop():empty stack");
}
//删除最后一个元素
elems.pop_back();
}
template <typename T>
T Stack<T>::top() const
{
if (elems.empty()){
throw out_of_range("Stack<>::top():empty stack");
}
//返回最后一个元素的副本
return elems.back();
}
int main(){
try{
Stack<int> intstack; //int 类型的栈
Stack<string> stringstack; //string 类型的栈
//操作int类型的栈
intstack.push(7);
cout<<intstack.top()<<endl;
//操作string类型的栈
stringstack.push("hello");
cout<<stringstack.top()<<endl;
stringstack.pop();
stringstack.pop();
}
catch(exception const& ex){
cerr<"Exception:ex.what()";
return -1;
}
}