嗯,上一篇已经介绍了面向过程编程的语法知识,接下来是最后的也是最重要的一个部分:

第三部分:基于对象的编程风格

1.构造函数的两种写法

比如我们有如下的类定义:

class Circle

{

public:

  Circle(float r);

private:

  float radius;

};

上面我们只是声明了构造函数,接下来要具体定义它。第一种写法很常见,也好理解,大家通常都是这么写的:

Circle::Circle(float r) { radius = r }

但是除了在函数体内部对类成员赋值的写法外,还有一种写法:类名::类名(形参表):内嵌对象1(形参表),内嵌对象2(形参表)... { 类的初始化 }。而且据说使用初始化列表比使用赋值语句的效率要高。 于是上面的构造函数可以写成如下形式:

Circle::Circle(float r):radius(r){}

恩,其实我还是比较喜欢第一种,然而有时候却必须用第二种:类成员有const(因为const成员只能被初始化,不能被赋值)和引用数据成员只能用初始化写法(第二种),不能被赋值写法(第一种)。

2.构造函数的重载

在一个类中可以定义多个构造函数,以便提供不同的初始化的方法,供用户选用。这些构造函数具有相同的名字,而参数的个数或参数的类型不相同。这称为构造函数的重载。 接下来看一个例子吧:

class Box

{

public :

  //定义一个无参的构造函数

  Box(){ height=10; width=10; length=10; };

  //定义一个有参的构造函数,用参数的初始化表对数据成员初始化

  Box(int h,int w,int len):height(h),width(w),length(len){ }

private :

  int height;  //高度

  int width;   //宽度

  int length;  //长度

}

好吧,这个例子是我网上找来的,而且我个人认为这是错误的示范,绝对的错误,这根本不是重载的正确用法,我觉得这种情况应该用默认参数技术!!那么什么时候才该使用构造函数的重载呢,你可以看看“C++ 我想这样用(五) ”中的重载例子。那个例子里的类才是真正需要重载构造函数的。

3.要不要析构函数

析构函数是与构造函数作用相反的函数。析构函数在下边3种情况时被调用:

a.对象生命周期结束,被销毁时;

b.delete指向对象的指针时,或delete指向对象的基类类型指针,而其基类虚构函数是虚函数时;

c.对象i是对象o的成员,o的析构函数被调用时,对象i的析构函数也被调用。

析构函数不返回任何值,没有函数类型,也没有函数参数。因此它不能被重载。一个类可以有多个构造函数,但只能有一个析构函数。

通常如果你的类成员都是一些“值类型”,换言之你的类成员都是“储值”的类型,如int char等,生存期过了就会被回收,那么你不需要写析构函数。反之如果你的类成员中有“储地址”的类型,比如指向new出来的空间的指针,那么你可一定要记得写析构函数,而且妥当的delete掉你new出来的空间。否则就引起了内存泄漏了。

class MyClass

{

private:

  char * _pName;

public:

  //这是你的构造函数

  MyClass(const char *name)

  {

    if (name)  {   _pName=new char[strlen(name)];  ......     };

  };

  //这时需要自己写出析构函数

~MyClass()

  {

    if (_pName)            delete [] pName;

  };

};

4.类的复制及四个默认函数

有人说,我没有写构造和析构函数啊,为甚还是可以正常的创建和销毁一个对象啊?嗯,好吧,我只能说编译器再一次给你擦屁股了。。。。。。 其实空类什么都不会有,所谓的默认构造函数、默认复制(拷贝)构造函数、默认赋值符操作符、默认析构函数是不会产生的,只有当用到这些函数或操作符时,编译器才会为我们产生所需要的函数或操作符。但是编译器产生的是什么特殊功能都没有的函数,为的只是让我们的程序能编译通过,如果你想要自己实现什么功能,如上面说的构造和析构,请自己实现吧~~~

构造和析构已经说过了,然而类中还有一个比较常用的功能就是复制,下面就说说和“复制”相关的拷贝构造函数和赋值符函数吧:

Triangular tri1(8);

Triangular tri2 = tri1;  //写法一

Triangular tri2(tri1);   //写法二

上述两种写法的形式虽然不同,但是意义是一样的,都是用已经存在的对象来创建新的对象,使两者内容一致。类不是int,怎么说复制就复制了呢?哪有那么容易呢?没错,我们能这样做是因为编译器为我们生成了默认的拷贝构造函数:

Triangular::Triangular(const Triangular& tri);

该默认函数是以成员逐一初始化的方式执行的,即类成员逐个复制。然而这种方法显然并不适合所有情况,如果我们的类成员有指针型的呢?没错,我们就只复制了地址,没有复制对应的空间,我们通常想要的是完整的拷贝,拷贝之后的tri1和tri2应该是互相无关的。这时我们需要自己来完成拷贝构造函数的编写。注意拷贝构造函数是参数唯一且固定的构造函数,所以没有返回值。在C++语言里:String   s2(s1);  和  String   s3   =   s1; 只是语法形式的不同,意义是一样的,都是定义加初始化,都调用拷贝构造函数。

除了上面这种完整的彻底的复制(深复制),我们有时仅仅需要简单的引用,即浅复制:

Triangular tri1(8);

Triangular tri2 ;

tri2 = tri1;   //这里完全不同与上面的写法一

这种情况下,我们已经有了两个存在了的对象,要做的仅仅是让tri2简单的与tri1有相同的引用。这时我们用到了赋值符函数:

Triangular & Triangular::operator = (const Triangular& RightSides)
{
    nSize=RightSides.nSize; //复制常规成员
    char *temp=new char[nSize]; //复制指针指向的内容 
    memcpy(temp,RightSides.pBuffer,nSize*sizeof(char));
    delete []pBuffer; //删除原指针指向内容  (将删除操作放在后面,避免X=X特殊情况下,内容的丢失)
    pBuffer=temp;   //建立新指向
    return *this
}

和拷贝构造函数的实现不一样,operator=();是把一个对象赋值给一个原有的对象,所以如果原来的对象中有内存分配要先把内存释放掉,而且还要检查一下两个对象是不是同一个对象,如果是的话就不做任何操作。什么????你说没看懂上面的像函数的东西是个啥??好吧,我也一样看不懂,因为这已经涉及到操作符重载了,是很高深的哦,后面会说到。总之在这部分要记住三个比较关键的函数:构造函数,析构函数,以及拷贝构造函数。这不是C++所特有的东西,是面向对象的基本概念,一般的面向对象语言里都有。比如java和C#,只不过语法上大同小异而已。

5.类的静态成员和静态成员函数

声明为static的类成员或者成员函数便能在类的范围内共同享,我们把这样的成员称做静态成员和静态成员函数。静态方法就是与该类相关的,是类的一种行为,而不是与该类的实例对象相关。静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。同样静态成员可以被初始化,但也只能在类体外进行初始化。我在网上找来了一个例子,比较直观:

#include <iostream> 
using namespace std; 
 
class Internet 

public: 
    Internet(char *name,char *address) 
    { 
        strcpy(Internet::name,name); 
        strcpy(Internet::address,address); 
        count++; 
    } 
    static void Internet::Sc()//静态成员函数 
    { 
        cout<<count<<endl; 
    } 
    Internet &Rq(); 
public: 
    char name[20]; 
    char address[20]; 
    static int count;//这里如果写成static int count=0;就是错误的 
}; 
 
Internet& Internet::Rq()//返回引用的成员函数 

    return *this; 

 
int Internet::count = 0;//静态成员的初始化 
void vist() 

    Internet a1("中国软件开发实验室","www.cndev-lab.com"); 
    Internet a2("中国软件开发实验室","www.cndev-lab.com"); 

void fn(Internet &s) 

    cout<<s.Rq().count; 

void main() 

    cout<<Internet::count<<endl;//静态成员值的输出 
    vist(); 
    Internet::Sc();//静态成员函数的调用 
    Internet b("中国软件开发实验室","www.cndev-lab.com"); 
    Internet::Sc(); 
    fn(b); 
    cin.get(); 
}

一定要理解了静态成员或静态成员函数的实际意义,才去使用它们,不然就是毫无意义的了。这里我吐槽下python,一般的语言都是这种定义,静态的类方法和非静态的类方法,可是python里面却有三种东西:实例函数,类函数,静态函数。第一个很好理解,就是那种普通的“类的非静态函数”了,但是后面两个真的就有些暧昧不清了,我是有些糊涂的,是的,曾经搞清楚了,因为我不会3个同时用到,所以很快又混淆了,不知道哪位大大解释下这种特立独行的意义。

C++ 我想这样用(六)的更多相关文章

  1. 初探JAVA中I/O流(二)

    1.缓冲输入文件 FileReader BufferedReader FileReader可以直接对文件进行读操作.但是简化编程,加快读取速度,我们加入了缓冲机制,使用了BufferedReader. ...

  2. centos启动流程[转]

    启动流程概览 在硬件驱动成功后,Kernel 会主动呼叫 init 程序,而 init 会取得 run-level 资讯: init 运行 /etc/rc.d/rc.sysinit 文件来准备软件运行 ...

  3. 【转】linux-系统启动流程详解

    第二十章.启动流程.模块管理与 Loader 最近升级日期:2009/09/14 1. Linux 的启动流程分析 1.1 启动流程一览 1.2 BIOS, boot loader 与 kernel ...

  4. SVN--VisualSVN server 服务端和 TortoiseSVN客户端的基础使用

    前言 在上一文http://www.cnblogs.com/wql025/p/5177699.html中,我们讲到了使用SVN的第一步,即下载.安装SVN的服务端软件--VisualSVN serve ...

  5. 关于win7系统中所有exe文件都被以word方式打开的解决方法

    手残一刻,电脑桌面所有的软件快捷方式都变成了word的打开方式,鼠标右键选中某exe文件也没打开方式那个选项, 第一次尝试: 在控制面板——默认程序中修改默认打开方式,但是没有找到解决方法

  6. 银行爱“IOE”爱得有多深

    本文由阿尔法工场欧阳长征推荐 导读:如果银行是一家海鲜酒楼,把IBM换掉相当于大搞一次装修,把Oracle换掉相当于把厨子和菜谱全部换掉,把EMC换掉相当于把放食材工具的储物间换个地方.难度在于,这海 ...

  7. Introduction to REST #Reprinted#

    from http://www.cnblogs.com/shanyou/archive/2012/05/12/2496959.html dudu的 HttpClient + ASP.NET Web A ...

  8. 摘录<小王子>——[法]安东·圣埃克苏佩里

    四 大人们都喜欢数字.你要是向他们说起一个新朋友,他们提出的问题从来问不到点子上. 他们绝不会问:"他的嗓音怎么样?他喜欢什么游戏?比如,他喜欢搜集蝴蝶标本吗?" 他们总是问你:& ...

  9. [Tensorflow实战Google深度学习框架]笔记4

    本系列为Tensorflow实战Google深度学习框架知识笔记,仅为博主看书过程中觉得较为重要的知识点,简单摘要下来,内容较为零散,请见谅. 2017-11-06 [第五章] MNIST数字识别问题 ...

  10. RESTful Web服务的操作

    1.首先我们说一下Http协议是无状态的 HTTP协议是无状态的,我们看到查到的用到的返回404,500,200,201,202,301.这些不是HTTP协议的状态码. 是HTTP的状态码,就是HTT ...

随机推荐

  1. 82. Remove Duplicates from Sorted List II

    题目: Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct  ...

  2. PHP优化杂烩

    讲 PHP 优化的文章往往都是教大家如何编写高效的代码,本文打算从另一个角度来讨论问题,教大家如何配置高效的环境,如此同样能够达到优化的目的. pool 一个让人沮丧的消息是绝大多数 PHP 程序员都 ...

  3. mac 下 apache设置

    windows下面的apache配置 apache是mac下是默认就有的,我们只需使用命令开启.暂停和重启就好了 sudo apachectl start sudo apachectl stop su ...

  4. 12 Useful “df” Commands to Check Disk Space in Linux

    On the internet you will find plenty of tools for checking disk space utilization in Linux. However, ...

  5. poj 1191 棋盘分割(dp + 记忆化搜索)

    题目:http://poj.org/problem?id=1191 黑书116页的例题 将方差公式化简之后就是 每一块和的平方 相加/n , 减去平均值的平方. 可以看出来 方差只与 每一块的和的平方 ...

  6. PL/SQL Developer自动补全SQL技巧

    s = SELECT t.* FROM t w = WHERE b = BETWEEN AND l = LIKE '%%' o = ORDER BY insw = IN (SELECT a FROM ...

  7. LA 3510 (置换 循环分解) Pixel Shuffle

    思路挺简单的,题目中的每个命令(包括命令的逆)相当于一个置换. 用O(n2k)的时间复杂度从右往左求出这些置换的乘积A,然后求m使Am = I(I为全等置换) 还是先把A分解循环,m则等于所有循环节长 ...

  8. WebApp开发之Cordova安装教程

    1 安装Cordova (Cordova开发环境的安装,包括所涉及的Node.js.Cordova CLI.JDK及Android SDK等,然后创建一个HelloWord项目.) 1.1 安装Nod ...

  9. JAVA安卓和C# 3DES加密解密的兼容性问题(2013年8月修改版)

    近 一个项目.net 要调用JAVA的WEB SERVICE,数据采用3DES加密,涉及到两种语言3DES一致性的问题, 下面分享一下, 这里的KEY采用Base64编码,便用分发,因为Java的By ...

  10. 【多端应用开发系列1.1.1 —— Android:使用新浪API V2】服务器Json数据处理——Json数据概述

    [前白] 一些基础的东西本系列中就不再详述了,争取尽量写些必不可少的技术要点. 由于本系列把Web Service 构建放到了第二部分,Android项目就采用新浪微博API v2作为服务器端. [原 ...