(转载)C++的一些要点

 

1.const 

示例代码:

#include <iostream>
int main(void)
{
 int x = 3;
 const int y = x;
 const int *p = &y;
 const int *c = &x;

 //error: l-value specifies const object
 //*p = 5;

 //error: cannot convert from 'const int *' to 'int *'
 //int *t = &y;

 //---------------------------------------------------
 int * const px = &x;

 //error: cannot convert from 'const int *' to 'int *const '
 //px = p;

 return 0;
}

const变量主要用于函数参数,使调用者不可改变传入的指针指向的内容。

 

2. volatile

下面的说明来自msdn,告诉编译器,这个变量可被其他进程修改,不要对其进行优化。

Objects declared as volatile are not used in optimizations because their value can change at any time. The system always reads the current value of a volatile object at the point it is requested, even if the previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.

One use of the volatile qualifier is to provide access to memory locations used by asynchronous processes such as interrupt handlers.

 

3.引用

变量的别名,对一个变量的引用的任何操作都是对本变量操作,必须初始化。

定义语法: 类型名 &引用名 = 被引用的变量;

引用是一个指针,但不用指针的语法。

引用必须指向一个变量;引用一旦指向一个变量,即不能指向其他的变量。

 

 

 

4.inline将把函数代码展开,同时作类型检查,而宏则不作类型检查。

 

5.namespace

命名空间是累计的,可跨越文件。

给命名空间起简名: namespace 别名   = 命名空间名;

using指示符: using namespace 命名空间名;

示例代码:

#include <iostream>
using namespace std;

namespace n1
{
int x = 1;
int fun(int x)
{
   cout << "in namespace 1" << endl;
   return x + 1;
}
namespace n2
{
   int x = 2;
   int fun(int x)
   {
    cout << "in namespace 2" << endl;
    return x + 2;
   }
}
}

int x = 3;
int fun(int x)
{  
cout << "in namespace std";
return x + 3; 
}

int g(int x)
{
{
   using namespace n1::n2;
   int x = 4;
   return n1::n2::fun(x);
}
}

int main(void)
{
cout << fun(x) << endl;
cout << n1::fun(n1::x) << endl;
cout << n1::n2::fun(n1::x) << endl;
cout << n1::n2::fun(n1::n2::x) << endl;
cout << g(3);
return 0;
}


6.函数的重载

用一个名字定义多个参数,各个参数用形参个数和类型区分。

必须在同一个命名空间中,不能用返回值区分。

示例程序:

#include <iostream>
using namespace std;

int abs(int x)
{
return x > 0 ? x : -x;
}

double abs(double x)
{
return x > 0 ? x : -x;
}

char abs(char x)
{
return x > 0 ? x : -x;
}

float abs(float x)
{
return x > 0 ? x : -x;
}

short abs(short x)
{
return x > 0 ? x : -x;
}

long abs(long x)
{
return x > 0 ? x : -x;
}

int main(void)
{
double a = 3.4;

//注释掉double类型的abs函数后
//error: ambiguous call to overloaded function
cout << abs(a);

return 0;
}

<补充> 
1.名字空间 完全限定名(Fully Qualified Names),两种解决方法: 
(1)使用typedef 把引用序列映射为一个较短的类型名以简化书写; 
(2)使用using声明和using指令 
using声明语法: 
using namespace::member; 
or 
using class::member; 
using指令语法: 
using namespace 名字空间名; 
名字空间一般用来分隔逻辑或业务上相互独立的模块。 
2.实现范型编程的方法 
(1)使用带参数的宏; 
(2)使用void*,例如qsort(); 
(3)使用通用的根类和虚函数,比如java中的Object; 
(4)使用模板技术。 
模板最适合实现范型编程,它不仅直观,而且是类型安全的,不会带来任何额外的运行时开销。 
template-->(实例化)Classes-->(实例化)Objects 
template-->(实例化)Functions 
如果设计的类的行为(接口)依赖于其所操作的数据类型,那么选用模板,否则选用继承和虚函数。 
3.模板实例化 
两个模板类或两个模板函数是类型等价的,当且仅当下列条件同时成立: 
(1)模板的名字相同; 
(2)类型实参完全相同(兼容的类型为不同类型); 
(3)非类型实参的值完全相等; 
(4)当类型实参为另一种模板时,它们也必须相同。 
模板的实例化发生在第一次使用该模板时,而不是在其定义或编译时。显式实例化由关键字template或typename后跟带模板实参的模板声明(不是定义)或类型映射组成。 
4.模板的特化(specialization) 
就是针对某种特别的类型参数重新实现基本的模板,一般是出于对时空效率的优化或者满足特殊的需要。例如:STL的vector<bool>。 
模板特化分为显式特化(Explict Specialization)和部分特化(Particial Specialization)(vc不支持),在范型编程的traints技术中使用比较多。  

(1)连接指示符:通知编译器,某个函数是由其它语言编写的。

语法:

1. extern "语言名" 函数原型;

2. extern "语言名"

{

   函数原型1;

   ...

   函数原型n;

}

3.extern "语言名"

{

   include 文件名

}

原因:C++语言编译器会对函数重载进行重命名(Name-Mangling);但是在C语言中,由于不允许出现同名的全局函数(静态全局函数除外),不需进行重命名。所以在程序中如果出现了extern "C" fun(int);就不应出现extern "C" fun(double);

例如:

extern "C" fun(int);
extern "C" fun(double);
int main(void)
{
fun(3);
fun(3.5);
return 0;
}

error C2733: second C linkage of overloaded function 'fun' not allowed

(2)函数重载的解析

根据函数调用中的实参,确定要执行的函数。

结果:

1.没有函数可调用(出错);

2.恰有一个可调用;

3.有多个可调用,二义性(在编译时发现)。

解析的时机:

1.函数调用时解析;

例如:

void fun(long);

void fun(int);

求:fun(3);

2.取函数地址。

例如:

void g(void (*fp)(long));

void g(void (*fp)(int));

求:g(f);

(3)实参类型转换

1.精确匹配。包含4种情形(其中a,b.c称为左值转换):

a.从左值到右值的转换

b.从数组到指针的转换

c.从函数到指针的转换

例如: int fun(int);

void g(int (*fp)(int));

求:g(fun);

d.限定修饰符转换

例如:int *q;

void fun(const int * p);

求:fun(q);

2.提升

a.带符号或不带符号的char,short类型转换为int型。

b.float   => double

c.bool   => int

3.标准转换

a.算术类型间的转换,这与提升a,b是一样的。

b.整型0到各种指针;各种指针 => void *

c.各种算术指针 => bool

4.用户自定义转换

标准转换序列:

0个或1个左值转换 -> 0个或1个提升或标准转换 -> 0个或1个限定修饰符转换

重载函数解析的过程:

1.确定候选函数集

a.调用点可见的同名函数

b.实参类型定义所属名字空间中的同名函数

2.确定可行函数集

a.实参个数 <= 形参个数,形参多出的必有缺省值。

b.有实参到形参的转换序列。

3.确定最佳可行函数。

 

(4)函数模板

1.功能不同或者是功能太大时不要使用函数重载。

所谓函数重载,是指自动生成各种类型函数的算法。

定义语法:template <模板参数表>

                    值类型 函数名 (形参表)

                    函数体

模板参数,由两类参数构成:

a.模板类型参数

声明方式: typename 标识符

表示一个特定类型。

b.模板非类型参数

声明方式: 通常的变量声明

表示一个值。

说明:

值类型,可以是内置类型,用户定义类型,模板类型参数

形参表,允许类型如上

函数表,定义的局部变量类型如上。

例如:

#include <iostream>
using namespace std;

template <typename T, int size>
T min(T (&a)[size])
{
int i;
T x = a[0];
for(i = 0; i < size; i++)
{
   if (x > a[i])
    x = a[i];
}
return x;
}

template <typename T>
T min(T *a, int size)
{
int i;
T x = a[0];
for(i = 0; i < size; i++)
{
   if (x > a[i])
    x = a[i];
}
return x;
}

int main()
{
int a[] = {1, 2, 3, -1, 5, 2, 4};
cout << min(a) << endl;
cout << min(a, 7) << endl;
}

模板实例化:

根据函数调用,自动生成函数。

说明:

显示指定模板参数语法:

函数名<实参名, ..., 实参名>(实参表);

例如:

template <typename T1, typename T2, typename T3>

T1   fun(T2 x, T3 y)

{

   ...

}

fun<int, int, double>(3, 2.5);

函数实参推演:从函数调用的实参确定模板参数的过程。

模板特化语法:

template <>

值类型 函数名<实际模板参数值>(形参表)

函数体

举例略。

函数模板的重载:

1.求候选函数集,较为复杂,略。

2.求可行函数集

3.最佳可行函数集

在写函数模板时,可以先写好特殊类型下的,再写一般的。例如:排序函数模板程序如下。

#include <iostream>
using namespace std;

template <typename T>
void sort(T *array, int n)
{
cout << "sort in template 1..." << endl;

//下标
int i, j;

//暂存待排序元素
T tmp;

for(i = 1; i < n; i++)
{
   tmp = array[i];
   j = i - 1;
   //寻找插入位置
   while(j >= 0 && array[j] > tmp)
   {
    array[j + 1] = array[j];
    j--;
   }
   array[j + 1] = tmp;
}
}

template <typename T1, typename T2>
void sort(T1 *array, int n, T2 fun)
{
cout << "sort in template 2..." << endl;

//下标
int i, j;

//暂存待排序元素
T1 tmp;

for(i = 1; i < n; i++)
{
   tmp = array[i];
   j = i - 1;
   //寻找插入位置
   while(j >= 0 && fun(array[j], tmp))
   {
    array[j + 1] = array[j];
    j--;
   }
   array[j + 1] = tmp;
}
}

int cmp(int a, int b)
{
return a > b;
}

int main()
{
int a[] = {1, 3, 5, 8, 9, 4, 6, 7, 2};
int size = sizeof(a) / sizeof(int);
sort(a, size);
for(int i = 0; i < size; i ++)
{
   cout << a[i] << endl;
}
cout << endl;

sort(a, size, cmp);
for(int i = 0; i < size; i ++)
{
   cout << a[i] << endl;
}
cout << endl;

double b[] = {1.0, 3.0, 5.0, 8.0, 9.0, 4.0, 6.0, 7.0, 2.0};
int dsize = sizeof(b) / sizeof(double);
sort(b, dsize);
for(int j = 0; j < dsize; j++)
{
   cout << b[j] << endl;
}
cout << endl;

sort(b, dsize, cmp);
for(int j = 0; j < dsize; j++)
{
   cout << b[j] << endl;
}

}

<补充> 
1.确定候选函数集

a.调用点可见的同名函数

b.实参类型定义所属名字空间中的同名函数

对于b项,老师举例:

namespace N 

class A{}; 
void f(A x){}; 
void f(int){}; 

void f(double){}

int main() 

N::A x; 
f(x); 
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值