C++的面向对象编程一

C++的面向对象编程一

类的学习笔记

C++不同于C的一个重要特性便是它具有面向对象的编程思想。那么谈到了面向对象,那从基础上就得先谈数据的封装了,也就是我们常说的类了。细节的学习应该可以从书上来学。参考书籍:《C++primer(第4版)》

这个学习笔记我想记录一些关于在设计一个类时所需要知道的事情。【浅见!】

定义一个类:

class Items{

         public :

                   int func1();

         private :

                   int val;

};

这样我们就粗略的定义了一个类。类中我们声明了一个成员函数和一个成员变量。

对于成员函数,C++希望我们在类的定义体之外定义成员函数【这里的原因不仅仅是为了好看,后面会讲到】,也就是实现具体细节。如下:

 

intItems::func1(){

         return val;

}

这样,实现了返回将类中的成员变量。这样,我们会发现两个问题,第一个返回的应该是Items对象里的val,可是val如果没有初始化怎么办。第二个问题是,返回的是哪个val。

于是我们需要修改我们的类,如下:

class Items{

         public :

                   Items (int i) : val( i ){}

                   int func1();

         private :

                   int val;

};

添加了一个构造函数。不添加的话,编译器会帮我们合成一个默认的构造函数。不过,良好的习惯是自己去写一个构造函数。这里涉及到了一个细节。构造函数里的初始化列表。只看构造函数,我们对比两个写法,一个如上,一个如下:

Items (inti) {

         val = i;

}

这两个写法所得到的结果是一样的,但是内部的运行机制就有所不同了。对于第一种写法,使用初始化列表,我们称val是在初始化。而对于下面的写法,在函数体内令val=i,这里我们称val在赋值。乍一看似乎没什么大不了,但有些变量偏偏可以初始化而不可以赋值。例如const变量和引用。因此,掌握初始化列表显得十分必要。

完成了val的初始化,那么回到func1函数,返回的是哪个val。这里的意思其实就是问为什么知道要返回对象中的val。我们看代码,一般我们会如下做:

ItemsaItems(1); // 得到一个对象

aItems.func1();//调用函数

很明显,成员函数都是需要一个对象进行调用的,而在传参数的时候,隐式地传了一个this指针过去,这个指针代表着调用者。为了理解,可以这样改代码:

intItems::func1(){

         return this->val;

}

this隐式地传了过来,是func1的一个形参。这样看起来便容易理解多了。一般可以省略,注意this是一个指针。

接着我们继续完善这个类。

class Items{

         public :

                   Items (int i) : val( i ){}

                   int func1();

                   int getVal() const;

                   int setVal(int i);

         private :

                   int val;

};

然后实现成员函数:

intItems::getVal() const {

         return val;

}

intItems::setVal(int i){

         val = i;

}

由于val是private的,那么要获取val的值和修改val。就得通过对应的get和set的函数。另外我们还在getval()函数那里添加了一个const修饰符。这个修饰符的意思是,在getVal()中,不可以修改this指针所指的对象。慎用该修饰符,比如在构造函数中使用const,那就是错误的。

不过,一直使用get和set显得有些麻烦,有一些类或函数如果频繁使用val,且能保证安全的话,那么可以允许他们去访问这些private函数。因此引入了友元的概念。friend修饰符。可以让一个类成为友元,也可以让一个类中的函数成为友元。这里有一个相互依赖的关系。即定义的先后次序。我们看如下,是一个正确的定义次序

class B{

         public :

                   …… // 省略必要

                   int func1(A& a);

}

class A{

         public :

                  ……// 省略必要

                  friendint B::func1(A& a); //声明类B中的func1()函数为友元

         private :

                   int val;

}

 

intB::func1(A& a){

         return a.val;

}

如上,首先我们必须现有类B,然后类B中有一个函数需要使用类A的private变量。因此,然后我们在类A中将B中的方法func1()声明为友元。然后func1的定义才可以出现。这也是一个建议成员函数在类的定义体外定义的原因之一。

然后,我们回到Items类,继续完善,我们可以加入static成员,这个让Items对象都共享的成员。区别于const,我将static理解为只有一份。使用“Items::”去调用他。然后有一个特殊整型的成员变量,可以在声明的时候初始化。

conststatic变量。

完成成员的定义,那么一个完整的类,你还需呀定义:

构造函数【形成对比】

Items ();

复制构造函数

Items (constItems&);

赋值操作符

Items &operate== (const Items&);

析构函数

~Items ();

完成这些基本就完成了类的定义,但为了可以给“用户”【后续解释】更好的体验,我们还需要重载操作符与转换。可重载的操作符包括:

+       -        *       /        %      ^       &      |       ~       !        ,        =       <       >       <=     >=     ++     --

<<     >>     ==     !=     &&   ||     +=     -=      /=     %=    ^=     &=    |=     *=     <<=  >>=  []       ()

->      ->*   new        new []  delete        delete[]

不能重载的操作符

::     .*               .                 ?:

对于一开始的学习,想到要重载这些操作符简直是恶梦,但是如果没有重载这些有时候又会是损失掉很多便利。这里就要提到前面说的用户。这里的用户是一个泛指的概念。对于一份代码而言,用户是程序员。对于一个程序,用户是操作人员。而对于一个类来说,用户就是代码了。在后面还会学到C++又一个重要的标志性东西,模版编程以及算法。而里面的很多算法就依赖于这些操作符的计算。

比如算法find函数,就需要要求类对象实现 == 操作符。初学复杂的东西往往是在你精通的路上不可或缺的部分,克服它,将收获更多。

如果需要写关于数据类型的类,那么实现隐式转换则更好,也更为难了。

那么到这里,就差不多完成了一个类,这对初学者来说,真真是臣妾做不到呀。

以上是我这几天的学习总结,如有错漏,欢迎纠正,万分感谢。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值