c++类的知识点(2)

前一随笔讲述了类的概念和类的基本理念(即数据封装,数据抽象.当然,不限于此,这里只概括到这里)

数据封装:

  类实现了对对象属性和方法的封装,即把它们都写在一个类中.使得二者都有了一个作用范围,即它们都是属于本类的属性和方法,至于其他类就没有对本类属性和方法的使用权.

数据抽象:

  编程是如何使用类对象内的属性和方法的呢?   ------接口!    通过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 } 

 

posted @ 2020-02-02 12:26  SSXFC  阅读(159)  评论(0编辑  收藏  举报