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 位操作基 ...
随机推荐
- C语言指针的概念
在计算机中,所有的数据都是存放在存储器中的.一般把存储器中的一个字节称为一个内存单元,不同的数据类型所占用的内存单元数不等,如整型量占2个单元,字符量占1个单元等,在前面已有详细的介绍.为了正确地访问 ...
- Android:Context的作用
Context字面意思上下文,Activity中我们直接用this代替,而到了一个button的onClick(View view)等方法时,我们用this时就会报错,改用ActivityName.t ...
- 简化PHP开发的10个工具
本文介绍了可以帮助简化 PHP 开发的11个项目,包括框架,类库,工具,代码. 1. CakePHP Development Framework CakePHP 是一个 PHP 的快速开发框架.它提供 ...
- CocoaPods requires your terminal to be using UTF-8 encoding
WARNING: CocoaPods requires your terminal to be using UTF-8 encoding. See https://github.com/CocoaPo ...
- poj 3790 Recursively Palindromic Partitions (递推)
题目 题意:求输入的数字的递归回文. 思路:答案等于这个数字一半之前的所有的 之和. #include <iostream> #include <cstdio> #includ ...
- dp,px转换
public static int dip2px(Context context, float dpValue) { final float scale = context.getRes ...
- UVa 10817 (状压DP + 记忆化搜索) Headmaster's Headache
题意: 一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师. 每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门. 要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两 ...
- UVa 1475 (二分+半平面交) Jungle Outpost
题意: 有n个瞭望塔构成一个凸n边形,敌人会炸毁一些瞭望台,剩下的瞭望台构成新的凸包.在凸多边形内部选择一个点作为总部,使得敌人需要炸毁的瞭望塔最多才能使总部暴露出来.输出敌人需要炸毁的数目. 分析: ...
- 学习PHP C扩展之面向对象开发方式 (转)
PHP OOP面向对象之C语言开发方式 学习PHP C扩展有一段时间了,PHP手册里大部分讲的PHP的函数开发方式,网上找OOP资料比较少,想起上个月测试redis 的时候,下载PHP扩展redis源 ...
- Java [Leetcode 319]Bulb Switcher
题目描述: There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off ...