前一随笔讲述了类的概念和类的基本理念(即数据封装,数据抽象.当然,不限于此,这里只概括到这里)
数据封装:
类实现了对对象属性和方法的封装,即把它们都写在一个类中.使得二者都有了一个作用范围,即它们都是属于本类的属性和方法,至于其他类就没有对本类属性和方法的使用权.
数据抽象:
编程是如何使用类对象内的属性和方法的呢? ------接口! 通过public权限的属性和方法才能对对象进行操作和使用. public内的东西就行时插板一样,人们可以用,但是插板内部实现如何呢? 不知道! 这样就对数据实现了抽象! 使用者只知道如何用,不知道它内部结构如何,如何运转! 这就对类对象实现了抽象.
下面记录类的继承:
面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。
被继承的是基类,继承的称为派生类.
一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名
继承也有多种类型,有保留的,无保留的. 分别是public protected private 继承.
如:基类是shape
派生类 class shape1:public shape{/*------*/}
派生之后派生类跟基类成员有啥关系呢?
按照继承类别分为:public protected private 三种
- 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
- 保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。基类的私有成员不能直接被派生类访问
- 私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。基类的私有成员不能直接被派生类访问
上面可以看出,凡是从基类中继承下来的私有成员都不能被派生类访问,而只能间接通过基类中继承下来的public 和protected 类型成员来访问.
这就引人思考,为何? 一种可能就是因为:类有私有成员的原因即不想让它以外的事物直接访问,派生的类也不例外啊. 而派生类就是为了继承基了,,所以取中,才有了这样的规则.
/******************************************************************埋个未知***********************************************************/
复杂继承:
继承的话,肯定会形成一颗继承树. 高级复杂的继承就不记录了..(没能力啊)
介绍重载(overload):
overload对我们来说可能比较熟悉,可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。
从上面百度百科介绍可以看出,它就是一个针对不同输入,运转操作此特定输入的函数的一种机制.
本质就是多态的一种运用.
具体的重载有两种:
1.函数重载
函数重载是一种特殊情况,C++允许在同一作用域中声明几个类似的同名函数,这些同名函数的形参列表(参数个数,类型,顺序)必须不同,常用来处理实现功能类 似数据类型不同的问题。
例子就不举了.
2.运算符重载
c++里面运算符也可以重载. 可以重载c++内大部分运算符. 运算符重载本质是:改变运算符的运算过程叫运算符重载。 因不同数据类型使用运算符,也就体现了多态性.
重载的运算符是带有特殊名称的函数,运算符重载本质上是函数调用. 函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。
类中成员函数重载运算符+
1 #include <iostream> 2 using namespace std; 3 4 class Box 5 { 6 public: 7 8 double getVolume(void) 9 { 10 return length * breadth * height; 11 } 12 void setLength( double len ) 13 { 14 length = len; 15 } 16 17 void setBreadth( double bre ) 18 { 19 breadth = bre; 20 } 21 22 void setHeight( double hei ) 23 { 24 height = hei; 25 } 26 // 重载 + 运算符,用于把两个 Box 对象相加 27 Box operator+(const Box& b) 28 { 29 Box box; 30 box.length = this->length + b.length; 31 box.breadth = this->breadth + b.breadth; 32 box.height = this->height + b.height; 33 return box; 34 } 35 private: 36 double length; // 长度 37 double breadth; // 宽度 38 double height; // 高度 39 }; 40 // 程序的主函数 41 int main( ) 42 { 43 Box Box1; // 声明 Box1,类型为 Box 44 Box Box2; // 声明 Box2,类型为 Box 45 Box Box3; // 声明 Box3,类型为 Box 46 double volume = 0.0; // 把体积存储在该变量中 47 48 // Box1 详述 49 Box1.setLength(6.0); 50 Box1.setBreadth(7.0); 51 Box1.setHeight(5.0); 52 53 // Box2 详述 54 Box2.setLength(12.0); 55 Box2.setBreadth(13.0); 56 Box2.setHeight(10.0); 57 58 // Box1 的体积 59 volume = Box1.getVolume(); 60 cout << "Volume of Box1 : " << volume <<endl; 61 62 // Box2 的体积 63 volume = Box2.getVolume(); 64 cout << "Volume of Box2 : " << volume <<endl; 65 66 // 把两个对象相加,得到 Box3 67 Box3 = Box1 + Box2; 68 69 // Box3 的体积 70 volume = Box3.getVolume(); 71 cout << "Volume of Box3 : " << volume <<endl; 72 73 return 0; 74 }
注意:运算符函数里面我们发现,obj.breadth等可以使用,为啥呢?
其实之前一直是有一个知识点被不全面理解的结果.
即:印象中,private的数据成员只能在类的成员函数中使用,无法通过类的对象直接访问!(错误理解)
正确的理解是:在类的成员函数中,可以直接访问私有成员。即只要在该类的成员函数中,无论是直接访问该类的私有数据成员,还是访问某个对象(必选是该类型)的私有数据成员,均是可以的!!!
这样就解释的通了.
还有一点特别之处:
运算符重载返回的对象并不会引起构造函数的调用.
友元运算符重载函数
1 #include <iostream> 2 using namespace std; 3 class shape 4 { 5 public: 6 int getarea(); 7 shape(){} 8 shape(int a,int b); // 简单的构造函数 9 shape(const shape &obj); // 拷贝构造函数 10 ~shape(); // 析构函数 11 int get(const shape &obj); 12 friend shape operator+(const shape &a,const shape &b); 13 private: 14 int breadth,height; 15 }; 16 17 int shape::getarea() 18 { 19 return breadth*height; 20 } 21 shape::shape(int a,int b) 22 { 23 breadth=a; height=b; 24 } 25 shape::~shape() 26 { 27 //cout<<"jslfaskfl"<<endl; 28 } 29 shape::shape(const shape &obj) 30 { 31 breadth=obj.breadth; 32 height=obj.height; 33 //cout<<"gou zao han shu bei diao yong"<<endl; 34 } 35 int shape::get(const shape &obj) 36 { 37 return obj.height*obj.breadth; 38 } 39 shape operator+(const shape &a,const shape &b) 40 { 41 shape obj; 42 obj.breadth=a.breadth+b.breadth; 43 obj.height=a.height+b.height; 44 return obj; 45 } 46 int main( ) 47 { 48 shape obj1(1,1); 49 shape obj2(2,2); 50 shape obj3=obj1+obj2; 51 //shape obj4=obj3; 52 cout<<obj3.getarea()<<endl; 53 return 0; 54 }
是不是运算符函数必须是以上两种之一呢?
未必!
1 #include <iostream> 2 using namespace std; 3 4 struct node 5 { 6 int a,b; 7 }; 8 node operator+(const node aa,const node bb) 9 { 10 node obj; 11 obj.a=aa.a+bb.a; 12 obj.b=aa.b+bb.b; 13 return obj; 14 } 15 int main( ) 16 { 17 node obj1; 18 node obj2; 19 obj1.a=1;obj1.b=2; 20 obj2.a=3; obj2.b=4; 21 node obj3=obj1+obj2; 22 cout<<obj3.a<<" "<<obj3.b<<endl; 23 return 0; 24 }
这里就是普通的函数,如果把struct 改成class 的话,非友元则只能访问公有数据.
/***********************下面介绍异常处理*********************/
如果你不确定某一段代码在运行时是否会出错,那么c++的一场处理就是很好的解决方法.
try,catch,throw
三个分别对应的是:
存放保护代码,一旦运行错误,则自动抛出相应异常.
捕获异常,即异常服务子程序.
抛出异常. 程序主动进行的异常抛出.
try{
}catch{
}
...
针对动态内存分配:
- 栈:在函数内部声明的所有变量都将占用栈内存。
- 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
有时候我们需要动态的内存分配,这时候就可以用new,和delete ,当然也可以用malloc 不过它只是分配额定的字节流,不会分配对象.
基本数据的分配和回收:
int *p=new int; delete p;
一维数组:
int *p=new int[100]; delete [ ] p;
二维数组的分配和回收:
int **p=new int *[100];
for(int i=0;i<100;i++) p[i]=new int[100];
回收:
for(int i=0;i<100;i++) delete [ ] p[i];
delete [ ] p;
由此看来二维的分配和回收要麻烦点.
/***********************************************/
全局变量和局部变量的选择是这样的:
有时有两个一样的变量,全局的,局部的,有时我们想用全局的,有时我们想用局部的,到底该咋办呢? 我们默认用的是当前作用域内的变量! 如若想在局域内用全局变量可用" ::vari_name "
1 #include<iostream> 2 using namespace std; 3 int i=222;//全局 4 int main() 5 { 6 int i=111;//局部 7 cout<<"i = "<<::i<<endl;//全局打印 8 cout<<"i = "<<i<<endl;//局部打印 9 return 0; 10 }
/*********************命名空间*************/
命名空间像是树节点一样,可以嵌套. 即像文件系统的文件设置一样,工作原理是相同的.
命名空间可以不连续,哪里需要可以在哪里临时扩充它.
在位运算中,要知道:整型,浮点型等数据的存储的符号位是最高位,不是最低位.
比如:int 有32位二进制位. 但是第31位(最高位)是符号位,它后面有31个数位,分别是0位,1位,...,30位.
如果想表示最大的那个数值,则可以使0 111111111111...111 即2^31-1 可以写为(1<<30)-1+(1<<30) 因为直接用(1<<31)-1会发生溢出的. 最小值是-2^31.
编译器中的整数默认是32位四字节的.想变成八字节可以在数字后面加入"ll"字段即可.
/*****************************模板******************************/
1 #define N 12+45 2 #define N(a,b) (a*2+b*3) 3 #define _for(i,a,b) for(int i=a;i<=b;i++) 4 const char *p="0123456789" //返回的是指针. 5 //模板函数 6 template<typename T> 7 T add(const T & a,const T &b) 8 { 9 return a+b; 10 } 11 //模板类 12 template<class T> 13 class add 14 { 15 public: 16 T set(T a,T b); 17 T area(); 18 private: 19 T length; 20 T height; 21 }; 22 template<class T> 23 T add<T>::area() 24 { 25 return length*height; 26 } 27 template<class T> 28 T add<T>::set(T a,T b) 29 { 30 length=a; height=b; 31 return a; 32 }