C++中冒号和双冒号的用法

                                     c++中冒号(:)和双冒号(::)的用法

(摘自网络)

这是C语言位域问题

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示

一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

 struct 位域结构名

{ 位域列表 };

 其中位域列表的形式为: 类型说明符 位域名:位域长度

 例如:

 struct bs

{

int a:8;

int b:2;

int c:6;

};  

位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:

 struct bs

{

int a:8;

int b:2;

int c:6;

}data;

 说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:

 1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

 struct bs

{

unsigned a:4

unsigned :0 /*空域*/

unsigned b:4 /*从下一单元开始存放*/

unsigned c:4

}

 在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。

 2. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:  

struct k

{

int a:1

int :2 /*该2位不能使用*/

int b:3

int c:2

};

 从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。

这篇文章将总结C/C++中的冒号的用法。

 1、位域定义

这个在前面关于位结构体的文章里说得够多的了,不再重复了。

 2、类构造函数(Constructor)的初始化列表

先说下什么叫构造函数吧(是不是啰嗦了?C++的人应该都知道了吧,还是以防万一一下)。所谓构造函数,就是与类同名的函数,它与普通函数的区别在于,它没有返回类型。

在构造函数后面紧跟着冒号加初始化列表,各初始化变量之间以逗号(,)隔开。下面举个例子。

class myClass

{

public :

myClass();// 构造函数,无返回类型,可以有参数列表,这里省去

~myClass();// 析构函数
 
int a;

const int b;

}

 

myClass::myClass():a(1),b(1)// 初始化列表

{

}

上面的例子展示了冒号的这个用法,下面对这个用法进行几点说明:

1)初始化列表的作用相当于在构造函数内进行相应成员变量的赋值,但两者是有差别的。

在初始化列表中是对变量进行初始化,而在构造函数内是进行赋值操作。两都的差别在对于像const类型数据的操作上表现得尤为明显。我们知道,const类型的变量必须在定义时进行初始化,而不能对const型的变量进行赋值,因此const类型的成员变量只能(而且必须)在初始化列表中进行初始化,即下面的代码将会出错:

myClass::myClass()

{

a = 1;// 没错,效果相当于在初始化列表中进行初始化

b = 1;// 出错,const变量不能进行赋值操作;

}

2)初始化的顺序与成员变量声名的顺序相同。

先看一下下面的程序:

myClass::myClass():b(1),a(b)

{

}

这样的执行结果a,b各是多少呢?b=1,a=1?不是,b=1而a是个随机数。这一点是相当重要的哦,一般在初始化列表中进行初始化时,初始化的顺序应与声明的顺序保持一致,防止出现不必要的错误。

3)对于继承的类来说,在初始化列表中也可以进行基类的初始化,初始化的顺序是先基类初始化,然后再根据该类自己的变量的声明顺序进行初始化。

 

3、声明基类。

假设我们重新定义一个类,继承自myClass类。定义方式如下:

class derivedClass : public myClass

{

// 略去

}

这里的冒号起到的就是声名基类的作用,在基类类名前面可以加public\private\protected等标签,用于标识继承的类型,也可以省略,省略的话,用class定义的类默认为private,用struct定义的类默认为public,至于具体各个标签有什么区别这里就不说了。

与初始化列表一样的,这里也可以声名多个基类,各基类之间用逗号(,)隔开。

 

4、条件语句(? :)

与?构成条件语句,作用相当于if else,如下;

int a,b,c;

a=3;

b=2;

c=a>b?a:b;// 如果a>b成立,则反a赋给c,否则把b赋给c

条件语句的结构为:

条件表达式?表达式1:表达式2

当条件表达式为true时,表达式的值为表达式1的值,否则为表达式2的值。

几点说明:

1)?:可以嵌套,但不推荐使用(难懂),下面的表达式你能看懂啥意思不?

int max = i>j ? i>k ? i : k : j>k ? j : k;

脑袋大了吧,呵呵。

2)?:具有很低的优先级

 

5、语句标签

通常跟goto配合使用,如:

step1: a = f1();

       ....

       goto step1;

这种作法也不是很推荐,原因在于它破坏了语句的顺序执行,这样的代价大家应该清楚吧。不过存在即为合理嘛,既然它还存在,肯定还是有它的用处有它的好处的,比如说,多层嵌套的退出(会比break continue直观一点吧),也可以避免重复代码之类之类的

 

6、switch语句中case后。

这个不说了,要是不会的话,我也没话可说了。

 

7、汇编指令模板

这个我也不懂,不班门弄斧了,可以参考一下:http://developer.e800.com.cn/articles/2006/43/1144846933898_1.html

改天学习一下。

 

(1)表示机构内位域的定义(即该变量占几个bit空间)

 

typedef struct _XXX{

 

          unsigned char a:4;

 

          unsigned char c;

 

} ; XXX

 

(2)构造函数后面的冒号起分割作用,是类给成员变量赋值的方法,初始化列表,更适用于成员变量的常量const型。

 

struct _XXX{

 

          _XXX() : y(0xc0) {}

 

};

 

(3) public:和private:后面的冒号,表示后面定义的所有成员都是公有或私有的,直到下一个"public:”或"private:”出现为止。"private:"为默认处理。

 

(4)类名冒号后面的是用来定义类的继承。

 

class 派生类名 : 继承方式 基类名

 

{

 

    派生类的成员

 

};

 

继承方式:public、private和protected,默认处理是public。

 

2.双冒号(::)用法

 

(1)表示“域操作符”

例:声明了一个类A,类A里声明了一个成员函数void f(),但没有在类的声明里给出f的定义,那么在类外定义f时,

就要写成void A::f(),表示这个f()函数是类A的成员函数。

 

(2)直接用在全局函数前,表示是全局函数

例:在VC里,你可以在调用API 函数里,在API函数名前加::

 

(3)表示引用成员函数及变量,作用域成员运算符

 

例:System::Math::Sqrt() 相当于System.Math.Sqrt()

 

 

 

(2)命名空间作用域符;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;即(2)直接用在全局函数前,表示是全局函数

在运算符等级中属于最高级的!

在你的问题中,似乎说的只是命名空间作用域符。

using namespace 命名空间名(如,abc);

表示在以下程序代码中所使用的标示符(如果此标示符在abc中定义)是abc中的,包括类型名(类),变量名,函数名,对象名。。。

using abc ::标示符(i);

只表示在以下代码中使用的标示符i是abc中的。

如果你要使用abc中的多个标示符的话,你就只能用

using abc::a;

using abc::b;

using abc::c;

...

等一个一个列举出来!

当然用using 语句是比较方便的

但是不安全

(1)using namespace;万一不同的两个命名空间中使用了同名的标示符,系统则不能判断,这个标示符是属于哪个命名空间的;

(2)using abc::;万一你的程序中也用到了一个函数(函数名与abc中的这个函数同名),那么系统也不能判断你使用的是abc中的那个函数,还是本程序中的那个函数;

最安全的办法(当然也是最繁琐的)

就是,每当你用到一个变量(函数...)时,你都要明确他的来历(即属于哪个命名空间)除非它没有命名空间

例如:

#include <iostream>

 

int main ()

{

std::cout << "hello, world!" << std::endl;

}

这里就用到了iostream文件中的两个对象(cout,endl)

因为C++标准库中绝大部分的函数,对象...都放在了命名空间std中

所以

上面的代码就等同于

#include <iostream>

using std::cout;

using std::endl;

int main ()

{

cout << "hello, world!" << endl;

}

 

#include <iostream>

using namespace std;

 

int main ()

{

cout << "hello, world!" << endl;

}

 

重新举个例子,再加以说明:

#include <iostream>

#include <string>

 

int main ()

{

int a;

std::string b;

 

std::cin >> a;

std::cin >> b;

 

std::cout << "hello, world!" << std::endl;

 

return 0;

}

 

 

1)using std::;

 

#include <iostream>

#include <string>

using std::cin;

using std::endl;

using std::string;

 

int main ()

{

int a;

string b;

 

cin >> a;

cin >> b;

 

std::cout << "hello, world!" << endl; //注意cout没用用using

 

return 0;

}

 

 

2)using namespace ;

#include <iostream>

#include <string>

using namespace std;

 

int main ()

{

int a;

string b;

 

cin >> a;

cin >> b;

 

cout << "hello, world!" << endl;

 

return 0;

}

其中cout endl cin string都是std中的!      

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值