1、重载函数

重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个运算符完成不同的运算功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。

方法一::重载函数,命名相同参数不同

1
2
3
4
5
6
7
8
9
10
11
12
void S();
void S(int);
void S(doubledouble=1.2);
void S(constchar*,constchar*);
void Max(intint);
//……
int main()
{
S(2.4);
return 0;
}
//S(2.4);的调用与S();S(int);S(double,double=1.2);S(constchar*,constchar*),的声明在同一域,即是可见的。

第一个动作是编译器从第一步选出的候选函数中调出可行函数(viable function)。可行函数的函数参数个数与调用的函数参数个数相同(如S ( int )),或者可行函数的参数可以多一些,但是多出来的函数参数都要有相关的缺省值(如 S (double , double =1.2 );)第二个动作是根据参数类型的转换规则将被调用的函数实参转换(conversion)成候选函数的实参。这里本着充分利用参数类型转换的原则,换句话说,尽可能的使用上参数类型转换。当然转换要以候选函数为转换的目标。上面的函数中只有两个是可行函数,它们分别是S ( int ); S ( double , double )。
如果依照参数转换规则没有找到可行函数,则该调用就是错误的,则说没有函数与调用匹配,属于无匹配情况(no match function)。

方法二::重载运算符

1
2
3
4
bool operator == (const SuperNode & A, const SuperNode & B) //重载 “==” 操作符,函数最后的 const 别忘了,否则会报错。
{
return A.k == B.k && A.snID == B.snID && A.list.size() == B.list.size();
}

自定义数据结构,常常需要重载判断符。

2、为什么C++语言用下划线用的那么多,下划线起什么作用

函数名、变量前后的_(一个下划线)、__(两个下划线)分别有什么用
为什么很多STL实现的表示符都用下划线开头?

This would fail to compile. Because users are allowed to define macros with names like comp and Compare and RandomAccessIterator, and because macros do not respect namespaces or scopes or other context, the standard library must use ugly names with leading underscores to avoid clashes. This is safe because it is forbidden for users to declare anything with names like __comp, so there can be no clash. Such names are called reserved names.

This is not a coding standard, it is the only way an implementation can prevent clashes with arbitrary user-defined names. For the convention to work users must never declare anything with a reserved name. You should absolutely not copy the convention for your own code.

加一个的变量一般都在complier的writer使用的,加两个 的are reserved for compiler 和 一个加上一个大写字母都是这样的情形

防止名字冲突


  1. 一种命名方式,没有实际意义,作用就是突出,防止重名
  2. 一般是宏名,在前面后面加__是为了防止和用户定义重名了
  3. 不是说了怕和宏重名了吗
  4. FILE_是预定义宏,_dbg_msg()是什么.我也不知道,记得看过.
  5. 相信ansi 有标准的说明,好像是一种约定,并非强制性的.但是在
    一些著名的程序中很多的利用. 相信如果有了固定的约定,那么我们还是遵守这样的约定为妙.
    至少别人和自己看以来更容易理解.
  6. 这不过是命名的习惯而已
  7. 在Function名称加_,一般情况下是系统内部的函数,当然自己也可以定义这样的函数。
  8. 一般只有已经广泛使用的系统库函数和宏才有资格使用甚至__打头,为的是不与用户定义的名字
    冲突,所以B.Stroustup在《The C++ Programming Language》中告诫我们一般不要使用
    或__
    打头的标志符,这也是一个编程风格的问题吧。
  9. FILE,LINE 都是与定义的宏,使用_ 和 __ 开始的函数一般都是专用的函数,一般都是于特定系统相关的,如果要想有更好的移植性,应该避免使用。

10. 包含两个下划线的名称,或者以下划线开头,后跟一个大写字母的名称,是C++标准库的保留名称,在程序中不应使用这类名称。编译器不会检查这类名称,用户只能在程序出错时发现有一个冲突的名称

3、模板template

函数声明格式

template < class(或typename) any(或任意符合规则的名称) >(如果还有其他类型名,就用逗号隔开)
返回类型 函数名(形参表);

函数定义和声明格式基本相同,形参表要加上形参名,分号改为函数体。

声明的例子:

template <class type1, class type2>
type1 add(type1,type2);
template <class type1, class type2>
type1 add(type1 a,type2 b)
{return a + (type1)b;}

也可以直接定义函数,不声明。
说明: template是一个声明模板的关键字,表示声明一个模板关键字class不能省略,如果形参类型多于一个 ,每个形参前都要加class <类型 形参表>可以包含基本数据类型或类类。

#include <iostream>
using std::cout;
using std::endl;
//声明一个函数模版,用来比较输入的两个相同数据类型的参数的大小,class也可以被typename代替,
//T可以被名称字代替,只要符合命名规则即可。
template <class T>
T min(T& x,T& y)
{ return(x<y)?x:y;}
int main( )
{
    int n1 = 2,n2 = 10;
    double d1 = 1.5,d2 = 5.6;
    cout<< "较小整数:"<<min(n1,n2)<<endl;
    cout<< "较小实数:"<<min(d1,d2)<<endl;
    system("PAUSE");
    return 0;
}

程序运行结果:
程序分析:main()函数中定义了两个整型变量n1 , n2 两个双精度类型变量d1 , d2然后调用min( n1, n2); 即实例化函数模板T min(T x, T y)其中T为int型,求出n1,n2中的最小值.同理调用min(d1,d2)时,求出d1,d2中的最小值.

4、泛型

泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。

泛型的定义主要有以下两种:

1.在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个别对象。(这是当今较常见的定义)
2.在程序编码中一些包含参数的类。其参数可以代表类或对象等等。(人们大多把这称作模板)不论使用哪个定义,泛型的参数在真正使用泛型时都必须作出指明。
一些强类型编程语言支持泛型,其主要目的是加强类型安全及减少类转换的次数,但一些支持泛型的编程语言只能达到部分目的。

C++ 的泛型(模板)

模板就是泛型的具体实现。java里没有模板,模板是c++的概念。应该是一回事吧 c++里叫模板,java叫泛型。
C++ 无法对泛型的类型参数进行约束。在编译时,每个被使用的封闭泛型类型(即是所有泛型参数的实际类型都已被指明的泛型)都会有独立的编码产生,编译器会在此时确保类型安全性。可是如果泛型要运用其泛型参数的某成员,而该泛型参数又不包含该成员的时候,编译器所产生的错误信息会看似与实际问题无关,增加出错的难度。

本质上的不同

泛型类的语法表面上类似于 C++ 中的模板工具。但是二者之间有着本质的区别。例如,Java 语言中的泛型不能接受基本类型作为类型形参 —— 只能接受引用类型。这意味着可以定义 List,但是不可以定义 List。(然而,自动装箱可以有助于使 List 在行为上类似于一个 int List。)

C++ 模板是有效的宏命令;当您使用 C++ 模板时,编译器使用提供的类型形参扩充模板。为 List 生成的 C++ 代码不同于为 List 生成的代码,因为 A 和 B 可能具有不同的运算符重载或内联方法。并且在 C++ 中,List 和 List 实际上是两个不同的类。

Java 泛型类以不同的方式实现。类型 ArrayList 和 ArrayList 的对象共享相同的类,并且只存在一个 ArrayList 类。编译器实施类型约束,并且运行时没有关于泛型的类型形参的任何信息。这是通过擦除 来实现的。
不过概念上是相同的,差别仅在于实现技术上。

什么是泛型编程?

简单来说,泛型编程,意思就是针对广泛类型的编程方式。具体类型可以有不同的实现方式,但是针对广泛类型编程,就能在需要调用时才指定参数类型或者调用类型。
泛型编程是一种基于发现高效算法的最抽象表示的编程方法。也就是说,以算法为起点并寻找能使其工作并且有效率的工作的最一般的必要条件集。
可以想象的是,很多算法都需要相同的必要条件集,并且这些必要条件集有不同的实现方式。STL标准模版库就是泛型编程的例子。

泛型函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
using namespace std;
template<typename T>
T * My_find(T *array,T n,T x){
T* p = array;
int i;
for(i=0;i<n;i++){
if(*p == x){
return p;
}
p++;
}
return 0;
}
int main(){
int a[] = {1,2,3,4,5,6,7,8,10};
int *result = My_find<int>(a,10,3);
cout<<(*result)<<"\n"<<endl;
return 0;
}

泛型类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>
using namespace std;

template<class T>
class Operate{
public:
static T add(T a,T b){
return a+b;
}
static T Mul(T a,T b){
return a*b;
}
static T Judge(T a,T b=1){
if(a>=0)
return a;
else
return a/b;
}
};
int main(){
int a,b,c,d,e,x,y,z;
a=1,b=2,c=3,d=4,e=5;
x=Operate<int>::add(a,b);
y=Operate<int>::Mul(c,d);
z=Operate<int>::Judge(e,b);
cout<<x<<" "<<y<<" "<<z<<" "<<endl;
return 0;
}

5、细节

system(“pause”)

请按任意键继续。。。

stdlib.h和cstdlib

int main(void)

命名空间namespace

未声明”cout””endl”标识符则需要包含,还需要使用这个相应的命名空间namespace std,也可以用std::cout,std::endl来代替,同理推广using namespace xxx与xxx::效果相同。

using是关键字。如果某个公司发明了一个函数,则就加上自己的命名空间放进去封装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include"stdlib.h"
#include"iostream"
using namespace std;
namespace A
{
int x(1);
void fun(){

cout<<'A'<<endl;
}


}
namespace B
{
int x(2);
void fun()
{
cout<<'B'<<endl;

}
void fun2()
{
cout<<'C'<<endl;
}
}
using namespace B;
int main(void)
{
cout<<A::x<<endl;
A::fun();
fun();
fun2();
}