C++知识黄金学习记录(二)
前言
所有的伟大,源于一个勇敢的开始,与博主一起坚持学习,“practice makes perfect”(熟能生巧)吧!
一、std详解
1.1std是什么?
std::是名称空间标示符,C++标准库中的函数或者对象都是在命名空间std中定义的,所以我们要使用标准函数库中的函数或对象都要使用std来限定。
1.2std使用举例
对象cout是标准函数库所提供的对象,而标准库在名字空间中被指定为std,所以在使用cout的时候要加上std::。这样编译器就会明白我们调用的cout是命名空间std中的cout。
1.3为什么要使用std
首先来看普通C++教程的写法:
#include<bits/stdc++.h>
using namespace std;
int main()
{
cout<<"我是CSDN-算法小学徒";
}
但在公司实际项目中你会发现使用的都是std::cout或者std::cin等,那为什么在实际项目中不建议使用using namespace std呢?
因为这样将标准命名空间全部打开,如果用了using namespace std,std名字空间下的所有变量、函数、类等都可以不加std::修饰而直接使用,在一些大的项目中很容易造成和其他的名字冲突,同时容易引起错误,在小项目里无关痛痒,但这种代码习惯其实不好,而且也失去了名字空间本身的意义了。
Extended explanation:
我们在 C 语言中,通过 static 可以限制名字只在当前编译单元内可见,在 C++ 中我们通过 namespace 来控制对名字的访问。C++中使用namespace定义作用域,所有变量都有作用域,以往C中定义一个变量,主要取决于定义的位置及修饰(如static),这样定义的作用域应用灵活度不高。
虽然C++兼容以往的做法,但博主更推荐使用namespace来定义作用域。
而且部分原来的C语法在C++中已经被取消(如使用static定义局部静态变量已经被C++取消了,使用未命名空间取代)~~~~
代码举例:
namespace
{
int i;
}
等价于 static int i;
接下来我们对namespace一探究竟:
1.4::(作用域)详解
"::"是运算符中等级最高的,它分为三种,分别如下:
一、 作用域符号:
作用域符号”::“的前面一般是类名称,后面一般是该类的成员名称,C++为例避免不同的类有名称相同的成员而采用作用域的方式进行区分。
例如:A,B表示两个类,在A,B中都有成员member。
那么:
1、A::member就表示类A中的成员member。
2、B::member就表示类B中的成员member。
二、全局作用域符号:
当全局变量在局部函数中与其中某个变量重名,那么就可以用::来区分:
#include <stdio.h>
int tot=0; //全局变量 0
int main()
{
int tot=10; //局部变量10
printf("total=%d\n",tot);//局部变量屏蔽了全局变量 所以输出结果是10
{
int count = 20;
printf("total=%d\n",::tot); //作用域符号指出引用全局变量0
}
return 0;
}
三、作用域分解运算符:用于在类之外定义函数。
::是C++里的作用域分解运算符,“比如声明了一个类A,类A里声明了一个成员函数void fun(),但没有在类的声明里给出fun的定义,那么在类外定义fun时,就要写成voidA::fun(),表示这个fun()函数是类A的成员函数。例如:
#include<iostream>
using namespace std;
class A
{
public:
void fun();
};
void A::fun()
{
cout << "fun() called";
}
int main()
{
A a;
a.fun();
return 0;
}
1.5Namespace基本知识
作用:C++中namespace简单来说就是用来解决标志符(如变量,函数,类等)的名字冲突问题的。
C++中namespace关键字定义了一个declarative region(声明区域),所以在一个namespace中声明的标志符和其他namespace中声明的同名标志符是没有名字冲突的。
解释:namespace(命名空间),简单理解为给类、变量、函数等限定一个区域。
namespace把一些类、变量、函数包含在一个空间中,在调用的时候使用作用域限定符号来调用,防止出现同名类、变量、函数无法分清的情况。也可以用来区分一个程序中各个模块的功能,类似于类。
1.6使用 namespace 中符号
使用名字空间中定义的符号有三种方式:
-
直接通过 namespace 作用域访问
-
using 声明指定某个符号在某个作用域下可见
-
using 编译指令指定名字空间中所有符号在在某个作用域下可见
1.7 namespace 可包含的成员
1.8直接通过 namespace 作用域访问
#include <iostream>
using namespace std;
// 第一个命名空间
namespace test1
{
void fun()
{
cout<<"This is the first test sample"<<endl;
}
}
// 第二个命名空间
namespace test2
{
void fun()
{
cout<<"This is the second test example" << endl;
}
}
int main ()
{
// 调用第一个命名空间中的函数
test1::fun();
// 调用第二个命名空间中的函数
test2::fun();
return 0;
}
1.9using 声明指定某个符号在某个作用域下可见
#include<iostream>
using namespace std;
namespace test1
{
int temp=10;
void fun()
{
cout<<"This is the first test sample"<<endl;
}
}
int main()
{
//fun符号只能在当前函数作用域内使用
using test1::fun;
fun();
//temp符号只能在当前函数作用域内使用
using test1::temp;
cout<<temp<<endl;
}
1.10 using 编译指令指定名字空间中所有符号在在某个作用域下可见
#include<iostream>
using namespace std;
namespace test1
{
int temp=10;
void fun()
{
cout<<"This is the first test sample"<<endl;
}
}
int main()
{
//fun符号只能在当前函数作用域内使用
using namespace test1;
fun();
cout<<temp<<endl;
}
1.11struct与class的区别
C++中,class与struct都可以定义一个类。他们有以下两点区别:
1.默认继承权限,如果不指定,来自class的继承按照private继承处理,来自struct的继承按照public继承处理;
2.成员的默认访问权限:class的成员默认是private权限,struct默认是public权限。
以上两点也是struct和class最基本的差别,也是最本质的差别!
1.12 C语言中.和->的区别
结构体变量用"." 来访问结构体成员
指向结构体的指针用 "-> "来访问其指向的结构体成员
1.13const和static const的区别:
一、全局的区别
const规定变量在全局中是只读的变量,并且它的值无法被修改。
static const规定变量在当前的模块中是只读的变量,无法在全局中被其他模块读取。
二、函数的区别
const只能通过构造函数初始化列表进行,并且必须有构造函数!
static const是静态的,属于类的静态成员函数。
1.14 友元函数
友元函数(friend function)介绍:
一个类的私有数据成员通常只能由类的函数成员来访问,而友元函数可以访问类的私有数据成员,也能访问其保护成员。
什么是友元函数?
友元函数(与成员函数相对)是定义在类外部,可以访问该类中的所有私有(private)成员和保护(protected)成员。指定函数为某个类的友元函数的方法是使用关键字friend。
friend <返回类型> <函数名> (<参数列表>);
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
为什么需要友元函数?
1、C++中引入友元函数,是为在该类中提供一个对外(除了他自己以外)访问的接口;
2、两个类要共享数据的时候,友元函数可以减少系统开销,调高效率;
3、运算符重载的某些场合需要使用友元函数;
4、通过友元函数,虚继承和私有构造函数可以让一个类不被继承;
友元函数注意事项
1.注意友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用"::“指示属于哪个类,只有成员函数才使用”::"作用域符号。
2.使用友元函数会破坏类的封装(所以需要尽量使用成员函数,除非不得已才使用友元函数哦)。
二、总结
每日一语:一个优秀的程序员会具备很多品质,例如拥有旺盛的好奇心,并有能把其转化为求知欲的能力又或者是强大的学习能力,扎实的基本功等等,但这一切都需要你主动去学习,去探索,去培养,没有人生下来就是天才,所谓天才都是在人生的旅途中慢慢发现自己的优势,并从芸芸众生中脱颖而出。从现在开始养成良好的代码习惯,尽量自己debug,提升代码的健壮性,不断巩固基础,培养自己抽象问题的能力,相信终有一天你会脱颖而出,成为自己想成为的那个人。