C++ 我想这样用(六)
嗯,上一篇已经介绍了面向过程编程的语法知识,接下来是最后的也是最重要的一个部分:
第三部分:基于对象的编程风格
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有相同的引用。这时我们用到了赋值符函数:
{
nSize=RightSides.nSize; //复制常规成员
char *temp=new char[nSize]; //复制指针指向的内容
memcpy(temp,RightSides.pBuffer,nSize*sizeof(char));
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++ 我想这样用(六)的更多相关文章
- 初探JAVA中I/O流(二)
1.缓冲输入文件 FileReader BufferedReader FileReader可以直接对文件进行读操作.但是简化编程,加快读取速度,我们加入了缓冲机制,使用了BufferedReader. ...
- centos启动流程[转]
启动流程概览 在硬件驱动成功后,Kernel 会主动呼叫 init 程序,而 init 会取得 run-level 资讯: init 运行 /etc/rc.d/rc.sysinit 文件来准备软件运行 ...
- 【转】linux-系统启动流程详解
第二十章.启动流程.模块管理与 Loader 最近升级日期:2009/09/14 1. Linux 的启动流程分析 1.1 启动流程一览 1.2 BIOS, boot loader 与 kernel ...
- SVN--VisualSVN server 服务端和 TortoiseSVN客户端的基础使用
前言 在上一文http://www.cnblogs.com/wql025/p/5177699.html中,我们讲到了使用SVN的第一步,即下载.安装SVN的服务端软件--VisualSVN serve ...
- 关于win7系统中所有exe文件都被以word方式打开的解决方法
手残一刻,电脑桌面所有的软件快捷方式都变成了word的打开方式,鼠标右键选中某exe文件也没打开方式那个选项, 第一次尝试: 在控制面板——默认程序中修改默认打开方式,但是没有找到解决方法
- 银行爱“IOE”爱得有多深
本文由阿尔法工场欧阳长征推荐 导读:如果银行是一家海鲜酒楼,把IBM换掉相当于大搞一次装修,把Oracle换掉相当于把厨子和菜谱全部换掉,把EMC换掉相当于把放食材工具的储物间换个地方.难度在于,这海 ...
- Introduction to REST #Reprinted#
from http://www.cnblogs.com/shanyou/archive/2012/05/12/2496959.html dudu的 HttpClient + ASP.NET Web A ...
- 摘录<小王子>——[法]安东·圣埃克苏佩里
四 大人们都喜欢数字.你要是向他们说起一个新朋友,他们提出的问题从来问不到点子上. 他们绝不会问:"他的嗓音怎么样?他喜欢什么游戏?比如,他喜欢搜集蝴蝶标本吗?" 他们总是问你:& ...
- [Tensorflow实战Google深度学习框架]笔记4
本系列为Tensorflow实战Google深度学习框架知识笔记,仅为博主看书过程中觉得较为重要的知识点,简单摘要下来,内容较为零散,请见谅. 2017-11-06 [第五章] MNIST数字识别问题 ...
- RESTful Web服务的操作
1.首先我们说一下Http协议是无状态的 HTTP协议是无状态的,我们看到查到的用到的返回404,500,200,201,202,301.这些不是HTTP协议的状态码. 是HTTP的状态码,就是HTT ...
随机推荐
- 82. Remove Duplicates from Sorted List II
题目: Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct ...
- PHP优化杂烩
讲 PHP 优化的文章往往都是教大家如何编写高效的代码,本文打算从另一个角度来讨论问题,教大家如何配置高效的环境,如此同样能够达到优化的目的. pool 一个让人沮丧的消息是绝大多数 PHP 程序员都 ...
- mac 下 apache设置
windows下面的apache配置 apache是mac下是默认就有的,我们只需使用命令开启.暂停和重启就好了 sudo apachectl start sudo apachectl stop su ...
- 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, ...
- poj 1191 棋盘分割(dp + 记忆化搜索)
题目:http://poj.org/problem?id=1191 黑书116页的例题 将方差公式化简之后就是 每一块和的平方 相加/n , 减去平均值的平方. 可以看出来 方差只与 每一块的和的平方 ...
- PL/SQL Developer自动补全SQL技巧
s = SELECT t.* FROM t w = WHERE b = BETWEEN AND l = LIKE '%%' o = ORDER BY insw = IN (SELECT a FROM ...
- LA 3510 (置换 循环分解) Pixel Shuffle
思路挺简单的,题目中的每个命令(包括命令的逆)相当于一个置换. 用O(n2k)的时间复杂度从右往左求出这些置换的乘积A,然后求m使Am = I(I为全等置换) 还是先把A分解循环,m则等于所有循环节长 ...
- WebApp开发之Cordova安装教程
1 安装Cordova (Cordova开发环境的安装,包括所涉及的Node.js.Cordova CLI.JDK及Android SDK等,然后创建一个HelloWord项目.) 1.1 安装Nod ...
- JAVA安卓和C# 3DES加密解密的兼容性问题(2013年8月修改版)
近 一个项目.net 要调用JAVA的WEB SERVICE,数据采用3DES加密,涉及到两种语言3DES一致性的问题, 下面分享一下, 这里的KEY采用Base64编码,便用分发,因为Java的By ...
- 【多端应用开发系列1.1.1 —— Android:使用新浪API V2】服务器Json数据处理——Json数据概述
[前白] 一些基础的东西本系列中就不再详述了,争取尽量写些必不可少的技术要点. 由于本系列把Web Service 构建放到了第二部分,Android项目就采用新浪微博API v2作为服务器端. [原 ...