C++ 我想这样用(五)
上一篇说了【C with Class】语法的第一部分,下面继续第二部分:
第二部分:面向过程的编程风格
什么是面向过程我想如果你还不知道,那你绝对不是C程序员!其实我个人感觉面向过程、模块式的C编程风格是最棒的范式,因为平时我们遇到的大多数问题,都可以用这种范式解决,而且设计相当的简洁明快,绝不拖泥带水,相反不停的折腾面向对象模型真的会让你离问题本质越来越远。不管你已经对面向过程范式多么熟悉了,C++环境下究竟还是有些不同的:
1.关于引用:
引用是现代编程语言中常有的一个概念,自然也是C++引入的新语言特性,是C++常用的一个重要内容。然而我不能不吐槽一句,难道就不能用个其他的操作符吗?于习惯使用C进行开发的朋友们,在看到c++中出现的&符号,可能会犯迷糊,因为在C语言中这个符号表示了取地址符,但是在C++中它却用来表示引用,于是乎产生了一大批混乱的写法:
#include <stdio.h>
int main(void)
{
int a = 0; // &a = 0x0012ff60
int *p = &*(int*)0x0012ff60;
printf("The value is: %d\n", *p);
return 0;
}
我真的不想贴出来,每每看到都想吐、、 总之这是一个很奇葩的现象,在一门已经有了指针这个究极武器的语言中再引入引用,真的是很混乱。我的建议是:
a)如果你是C++程序员,用好你的引用吧,别来玩弄指针了;
b)相反你是C程序员,那请自爱,远离引用!!至少C with Class里是禁止使用的。
2.new和delete的使用注意
差不多到目前为止,new和delete操作符是我接受的唯一的C++里面的东西,既然为了面向对象不得不接受他们,那么就一定要用好他们。
new用法:
1. 开辟单变量地址空间
1)int *a = new int; //开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a.
2)int *a = new int(5); //作用同上,但是同时将整数赋值为5
2. 开辟数组空间
int *a = new int[100]; //开辟一个大小为100的整型数组空间
delete用法:
1. delete a; //释放单个int的空间
2. delete [] a; //释放int数组空间
一定要注意delete 和delete[] 的区别,C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]。 关于 new[] 和 delete[],其中又分为两种情况:(1) 为基本数据类型分配和回收空间;(2) 为自定义类型分配和回收空间。
请看下面的程序:
#include <iostream>;
using namespace std; class T {
public:
T() { cout << "constructor" << endl; }
~T() { cout << "destructor" << endl; }
}; int main()
{
const int NUM = 3; T* p1 = new T[NUM];
cout << hex << p1 << endl;
// delete[] p1;
delete p1; T* p2 = new T[NUM];
cout << p2 << endl;
delete[] p2;
}
大家可以自己运行这个程序,看一看 delete p1 和 delete[] p1 的不同结果,我就不在这里贴运行结果了。从运行结果中我们可以看出,delete p1 在回收空间的过程中,只有 p1[0] 这个对象调用了析构函数,其它对象如 p1[1]、p1[2] 等都没有调用自身的析构函数,这就是问题的症结所在。如果用 delete[],则在回收空间之前所有对象都会首先调用自己的析构函数。基本类型的对象没有析构函数,所以回收基本类型组成的数组空间用 delete 和 delete[] 都是应该可以的;但是对于类对象数组,只能用 delete[]。对于 new 的单个对象,只能用 delete 不能用 delete[] 回收空间。
所以一个简单的使用原则就是:new 和 delete、new[] 和 delete[] 对应使用。
3.函数参数默认值
没错,很多C程序员早就知道C++可以给函数参数分配默认值,如果调用时不指定,就用默认值。我觉得这个特性真的很不错,可以为设计API提供极大方便,然而C里面是没有的,如果你的强迫症不是特别严重,我觉得可以接受这个特性,如果不幸中枪也不要担心,其实用C我们也可以模拟实现这一特性,就是用最犀利的Macro!!
具体的做法如下:
#include<stdio.h> enum{ plain=,italic=,bold= }; void printString(const char* message, int size, int style) { printf("%s %d %d\n",message,size,style); } #define PRINT_STRING_1_ARGS(message) printString(message, 18, italic) #define PRINT_STRING_2_ARGS(message, size) printString(message, size, italic) #define PRINT_STRING_3_ARGS(message, size, style) printString(message, size, style) #define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4 #define PRINT_STRING_MACRO_CHOOSER(...) \ GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \ PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, ) #define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__) int main(int argc, char * const argv[]) { PRINT_STRING("Hello, World!"); PRINT_STRING("Hello, World!", ); PRINT_STRING("Hello, World!", , bold); return ; }
好吧,确实很复杂,其实可以适当简化的,不过如果你真的是想设计库,上面的完整写法真的是超赞的哦,而且可移植性很高呢,当然这不是我想出来的,原链接在这里:
http://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros
4.inline函数
以前的C是没有inline这个东西的,对于一些要频繁使用的小函数,我们常常把他们写成宏函数,这样可以降低函数展开的开销。但是C++是有的,于是很多的编译器也为C加上了这个拓展,比如gcc,可是C99出现了,给C加上了这一特性。原本一切都好了,然而杯具的是C99的inline和许多编译器以前加的那个用法是不完全相同的,如果你习惯了gcc风格的inline,请一定要注意啊,我在网络上找到了这个,看看吧:
http://blog.163.com/zhaojie_ding/blog/static/172972895200811545032240
5.重载函数
现实生活中的一个词可能有多种含义,比如,洗衣服、洗头、洗车,都有一个洗字,但是他们的操作方式是不一样的。函数也一样,有时候它们的操作不完全一样但是名字一样,这就是重载函数。
重载函数就是,两个以上的函数取相同的函数名,但是函数形参的个数或者类型不同,编译器会根据实参与形参的类型和个数进行最佳匹配,自动确定调用哪一个函数。为什么要有重载函数呢?因为如果没有重载函数,那么对不同类型的数据进行类似的操作也要定义不同名称的函数,比如加法函数,就必须对整数加法和浮点数加法分别定义不同的函数名:
int nadd(int a, int b);
float fadd(float a, float b);
这样调用需要记住的函数名太多,而且功能类似,很不方便。这是C++的一个语法特性,这一点在创建类时编写构造函数时是很实用的。比如有一个叫三角形的类triangle,你可以用一个至多个参数来创建:
new triangle(x); // 创建了一个等边三角型,边长x
new triangle(x,y); // 创建了一个等腰三角形,底x,腰y
new triangle(x,y,z); // 创建了一个一般三角形
想做到上面的,只要你重载了三个构造函数就可以了。
6.模版函数
有时候我们使用重载函数还不能达到最优的效果,比如,两个求绝对值的函数:
int abs(int x)
{
return x<0 ? -x:x;
}
double abs(double x)
{
return x<0 ? -x:x;
}
大家观察下这两个函数,这两个函数只是返回值类型和参数类型不同,功能完全一样,如果能有办法写一段通用的代码适用于多种不同的数据类型,就是不用像上面那样写两个函数而只是一段代码就能实现两个函数的功能,那代码的复用性不是更高了吗?开发效率也会提高的。这就要函数模板来实现了。函数模板的定义形式是:
template <typename 标识符>
函数定义
没错,模版函数已经设计到模版了,而且最重要的是,这里面已经不是OOP的思想了,而是更高层次的一种范式,即:泛型编程。显然这离C with Class太遥远。
C++ 我想这样用(五)的更多相关文章
- python2.7练习小例子(二十五)
25):题目:有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁.问第4个人岁数,他说比第3个人大2岁.问第三个人,又说比第2人大两岁.问第2个人,说比第一个人大两岁.最后问第一个人,他 ...
- C语言经典算法五个人问岁数!——————【Badboy】
有5 个人坐在一起,问第五个人多少岁?他说比第4 个人大2 岁.问第4 个人岁数.他说比第3 个人大2 岁.问第三个人,又说比第2 人大两岁.问第2 个人.说比第一个人大两岁.最后问第一个人.他说是1 ...
- Nhibernate系列学习之(五) 存储过程
NHibernate也是能够操作存储过程的,不过第一次配置可能会碰到很多错误. 一.删除 首先,我们新建一个存储过程如下: CREATE PROC DeletePerson @Id int AS DE ...
- 微信小程序首次官方分享的纪要
先交代备注: 这次有关小程序的分享只有技术的 QA环节,其他如产品.入口.流量.与公众号的整合等等,回答都是暂时无法给出答案或不确定: 小程序最终发布时间官方也还未确定,不过说应该就是近期: 小程序的 ...
- 一道算法题目, 二行代码, Binary Tree
June 8, 2015 我最喜欢的一道算法题目, 二行代码. 编程序需要很强的逻辑思维, 多问几个为什么, 可不可以简化.想一想, 二行代码, 五分钟就可以搞定; 2015年网上大家热议的 Home ...
- 12个非常实用的JavaScript小技巧
在这篇文章中将给大家分享12个有关于JavaScript的小技巧.这些小技巧可能在你的实际工作中或许能帮助你解决一些问题. 使用!!操作符转换布尔值 有时候我们需要对一个变量查检其是否存在或者检查值是 ...
- 苹果版App开发心得
这几个月中做的工作包括网站开发.安卓App开发和苹果App开发,前两者用的语言都是我熟悉的java,故苹果知识的学习,较安卓知识的学习,多出「语言基础」一块,其他方面差不多. 之前发过安卓那篇,如感兴 ...
- JAVA经典算法40题(供面试所用)
[程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 1.程序分析: 兔子的规律为数 ...
- C语言经典例题100
C语言经典例题100 来源 http://www.fishc.com 适合初学者 ----------------------------------------------------------- ...
- delphi.位操作
位操作网上有很多介绍,请上网google/baidu,比如: 位操作技巧实例大全: http://blog.csdn.net/g_spider/article/details/5750665 位操作基 ...
随机推荐
- POJ1986 DistanceQueries 最近公共祖先LCA 离线算法Tarjan
这道题与之前那两道模板题不同的是,路径有了权值,而且边是双向的,root已经给出来了,就是1,(这个地方如果还按之前那样来计算入度是会出错的.数据里会出现多个root...数据地址可以在poj的dis ...
- Java API —— 多线程(2)
1.JDK5中Lock锁的使用 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对 ...
- Classpath entry org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER will not be exported
打开navigator,修改下面的classpath文件: 将<classpathentry kind="con" path="org.maven.ide.ecli ...
- hadoop2 环境的搭建(手动HA)
1.手工切换ha的环境的搭建(比hadoop1多出来journalnode的配置) namenode:hadoop110和hadoop111 datanode:hadoop112.hadoop113. ...
- Java中常见几种数据库连接方法
1:引入java.sql数据包; import java.sql.*; 2:加载JDBC驱动程序 Class.forName(JDBC驱动包的名字).newInstance(); 3:产生Co ...
- Qt之QuaZIP(zip压缩/解压缩)
简述 QuaZIP是使用Qt/C++对ZLIB进行简单封装的用于压缩及解压缩ZIP的开源库.适用于多种平台,利用它可以很方便的将单个或多个文件打包为zip文件,且打包后的zip文件可以通过其它工具打开 ...
- hMailserver设置外部反病毒扫描程序
刚在5dmail上发现有人提出一个问题,他在hmailserver的外部病毒扫描程序中使用了瑞星那个娱乐货,结果呢,说瑞星太勇猛了,所有附件都认为病毒了,这是怎么个情况呢? 先从hmailadmin里 ...
- UVa 11609 (计数 公式推导) Teams
n个人里选k个人有C(n, k)中方法,再从里面选一人当队长,有k中方法. 所以答案就是 第一步的变形只要按照组合数公式展开把n提出来即可. #include <cstdio> typed ...
- 如何用css3实现风车效果
前面讲过css3可以替代很多js实现的效果,其实很多时候纯css3甚至可以替代图片,直接用css3就可以画出一些简单的图片.虽然css3画出来的图片效果可能不如直接用图片的好,实现起来也比较复杂,最麻 ...
- HDU 5294 Tricks Device (最短路,最大流)
题意:给一个无向图(连通的),张在第n个点,吴在第1个点,‘吴’只能通过最短路才能到达‘张’,两个问题:(1)张最少毁掉多少条边后,吴不可到达张(2)吴在张毁掉最多多少条边后仍能到达张. 思路:注意是 ...