【基础知识】c++中:与::的用法

单引号 :

1. 继承

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

如:

class BaseClass
    {
    public :
     BaseClass();// 构造函数,无返回类型,可以有参数列表,这里省去
    ~BaseClass();// 析构函数
    }
    
class SubClasspublic BaseClass()
    {
    }

2. 初始化参数列表

使用初始化列表的原因

初始化类的成员有两种方式,一是使用初始化列表,二是在构造函数体内进行赋值操作

主要是性能问题,对于内置类型,如int, double等,使用初始化列表和在构造函数体内初始化差别不是很大,但是对于类类型来说,最好使用初始化列表,为什么呢?使用初始化列表少了一次调用默认构造函数的过程,这对于数据密集型的类来说,是非常高效的
所以一个好的原则是,能使用初始化列表的时候尽量使用初始化列表。

必须使用初始化列表的时候

除了性能问题之外,有些时候初始化列表是不可或缺的,以下几种情况时必须使用初始化列表

1.常量成员,const修饰的类成员变量,因为常量只能初始化不能赋值,所以必须放在初始化列表里面
2.引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面
3.没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化

class Date
{
public:
    Date(int year)
        : _year(year)
    {}
private:
    int _year;
};

class Time
{
public:
    Time(Date& d)
    {
        _d = d;
    }
private:
    Date _d;
};

以上代码无法通过编译,因为Time的构造函数中 _d = d这一行实际上分成两步执行:
首先调用Date的默认构造函数来初始化_d
由于Date没有默认的构造函数,所以无法执行初始化_d,故而编译错误。
正确的代码如下,使用初始化列表代替赋值操作

class Time
{
public:
    Time(Date& d)
        : _d(d)
    {}
private:
    Date _d;
};

成员变量顺序

成员是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的。

如下代码:

class Fun
{
public:
    //先初始化_x,再初始化_y
    Fun(int tmp)
        : _x(tmp)
        , _y(_x)
    {}    
private:
    int _x;
    int _y;
};

再看下面的代码:

class Fun
{
public:
    //_y未定义
    Fun(int tmp)
        : _y(tmp)
        , _x(_y)
    {}    
private:
    int _x;
    int _y;
};

这里 _x 的值是未定义的,虽然 _y 在初始化列表里面出现在 _x 前面,但是 _x 先于 _y 定义,所以必须先初始化 _x,而 _x 由 _y 初始化,此时 _y 尚未初始化,所以导致 _x 的值未定义。一个好的习惯是,按照成员定义的顺序进行初始化 。

参数列表初始化示例代码

示例1

TEST( int AA, int BB ):a(AA),b(BB)
{
}
//相当于
TEST( int AA, int BB)
{
a=AA;
b=BB;
}

示例2

class String
{
    public:
    	String(const String& s)
            :_str(new char[strlen(s._str)+1])
        {
            strcpy(_str,s._str);
        }
    	~String()
        {
            delete [] _str;
        }
    private:
    	char *_str;
};
//相当于
class String
{
    public:
    	String(const String& s)
        {
            _str=new char[strlen(s._str)+1];
            strcpy(_str,s._str);
        }
    	~String()
        {
            delete [] _str;
        }
    private:
    	char *_str;
};

示例3

class Point
{
private:
    int X,Y;
public:
    Point(int xx=0,int yy=0)//类Point的构造函数
    {
        X=xx;
        Y=yy;
    }
    //拷贝构造函数,Point(Point &p)表示p是point类的一个对象,
    //而&p则是这个对象的引用(也就是这个对象的地址)。这是拷贝构造函数的规定,不能变。
    Point(Point &p);
 
    int GetX(){return X;}
    int GetY(){return Y;}
};
 
Point::Point(Point &p)//拷贝构造函数的实现,::来表示他是类的构造函数(成员函数)
{
    X=p.X;
    Y=p.Y;
    cout<<"Point拷贝构造函数被调用!"<<endl;
}
 
class Line
{
private:
    Point p1,p2;
    double len;
public:
    Line(Point xp1,Point yp2);//类Line的构造函数
    Line(Line &L);
    double GetLen(){return len;}
};
 
 
Line::Line(Point xp1,Point yp2):p1(xp1),p2(yp2)//初始化列表方式
{
    cout<<"Line构造函数被调用!"<<endl;
    double x=double(p1.GetX()-p2.GetX());
    double y=double(p1.GetY()-p2.GetY());
    len=sqrt(x*x+y*y);
}
Line::Line(Line &L):p1(L.p1),p2(L.p2)
{
    cout<<"Line拷贝构造函数被调用!"<<endl;
    len=L.len;
}
void main()
{
    Point myp1(1,1),myp2(4,5);
    Line line(myp1,myp2);
    Line line2(line);
    cout<<"The Length of the line is:";
    cout<<line.GetLen()<<endl;
    cout<<"The Length of the line2 is:";
    cout<<line2.GetLen()<<endl;
 
}

3. 位域

该种形式出现于结构体或共用体的定义中,是位域定义的标准形式。
其使用方式为

struct name
{
	type var_name : n;
};

含义为,在结构体name汇总,成员变量var_name占用空间为n位。
n为正整数,其值必须小于type类型占用的位数。比如type如果是int,占4字节32位,那么n必须是1~31之间的整数。
对于位域类型的成员,在赋值时如果实际值超过n位所能表达的范围,那么超出部分将会被截掉,只保存低位值。如int var:4,本身只有4位的空间,如果赋值var = 20, 由于20的二进制值为10100,实际为五位,这时var实际被赋值的就是低四位,0100,即4。

4. 遍历

vector<vector<int>>& rectangles
for(vector<int> rectangle : rectangles) {
            //获取坐标
            left = min(left, rectangle[0]);
            low = min(low, rectangle[1]);
            right = max(right, rectangle[2]);
            high = max(high, rectangle[3]);
            }

双引号 ::

1. 类作用域,用来标明类的变量、函数

作用域符号::的前面一般是类名称,后面一般是该类的成员名称,C++为例避免不同的类有名称相同的成员而采用作用域的方式进行区分
如:A,B表示两个类,在A,B中都有成员member。那么
A::member就表示类A中的成员member
B::member就表示类B中的成员member

	Human::setName(char* name);

2. 命名空间作用域,用来注明所使用的类、函数属于哪一个命名空间的

	std::cout << "Hello World" << std::endl;

3. 全局作用域,用来区分局部、全局的。

最容易被忽视的一种,很多时候写了一个全局函数或者想要调用一个全局函数,却发现IDE或者Editor找不到该函数,原因是因为局部函数与想要调用的全局函数名字一样,然后找了很久也找不到原因,甚至放弃解决的。其实原因就是因为 【局部变量/函数】 与 【全局变量/函数】 的名字相同,IDE无法区分,这时候加上 :: 就可以调用到全局函数,访问到全局变量了。

全局作用域符号:当全局变量在局部函数中与其中某个变量重名,那么就可以用::来区分如:

char zhou;    //全局变量
void sleep()
{
      char zhou;    //局部变量
      char(局部变量) = char(局部变量) *char(局部变量) ; 
     ::char(全局变量) =::char(全局变量) *char(局部变量);

示例

Linux下串口打开、关闭的api

// fcntl.h文件下的全局函数open 
open (const char *__path, int __oflag, ...)

// unistd.h文件下的全局函数
extern int close (int __fd);

由于每次找api是一件非常浪费coding时间,而且是没多大意义的事情,我现在要将这个函数封装成一个我自己的个人串口库WzSerialPort.h、WzSerialPort.cpp

// WzSerialPort.h
class WzSerialPort
{
public:
	// ...
	bool open();
	void close();
	// ...
};

注意以下的cpp文件,如果没有 :: 则会报错误,因为WzSerialPort库中有函数open和close,跟全局函数open和close名字相同,如果不做全局与局部的区分,则无法调用到全局函数

// WzSerialPort.cpp
bool WzSerialPort::open()
{
	if( ::open(portname,O_RDWR|O_NOCTTY|O_NONBLOCK) != -1 )
		return true;
	else
		return false;
}
void WzSerialPort::close()
{
	::close(fd);
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值