::
::
在C++
中表示作用域,和所属关系。
::
是运算符中等级最高的,它分为三种,分别如下:
作用域符号:
作用域符号::
的前面一般是类名称,后面一般是该类的成员名称,C++
为例避免不同的类有名称相同的成员而采用作用域的方式进行区分。
例如:A
,B
表示两个类,在 A
,B
中都有成员 member
。
那么:
- 1、
A::member
就表示类A
中的成员member
。 - 2、
B::member
就表示类B
中的成员member
。
全局作用域符号:
全局作用域符号::
当全局变量在局部函数中与其中某个变量重名,那么就可以用 ::
来区分,例如:
char zhou; //全局变量
void sleep()
{
char zhou; //全局变量
char(局部变量) = char(局部变量)*char(局部变量);
::char(全局变量) =::(全局变量) *char(全局变量)
}
作用域分解运算符:
::
是 C++ 里的作用域分解运算符,“比如声明了一个类A
,类A
里声明了一个成员函数 void f()
,但没有在类的声明里给出f的定义,那么在类外定义 f 时,就要写成 voidA::f()
,表示这个 f()
函数是类 A 的成员函数。例如:
class CA
{
public:
int ca_var;
int add(int a, int b);
int add(int a);
}
//那么在实现这个函数时,必须这样写:
int CA::add(int a, int b)
{
return a + b;
}
//另外,双冒号也常常用于在类变量内部作为当前类实例的元素进行表示,比如:
int CA::add(int a)
{
return a + ::ca_var;
}
//表示当前类实例中的变量ca_var。
C++ 简介
C++
是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。
C++
被认为是一种中级语言,它综合了高级语言和低级语言的特点。
C++
是由 Bjarne Stroustrup
于 1979 年在新泽西州美利山贝尔实验室开始设计开发的。C++ 进一步扩充和完善了 C 语言,最初命名为带类的C,后来在 1983 年更名为 C++。
C++
是 C
的一个超集,事实上,任何合法的C
程序都是合法的 C++
程序。
注意:使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。
面向对象程序设计
C++ 完全支持面向对象的程序设计,包括面向对象开发的四大特性:
- 封装
- 抽象
- 继承
- 多态
标准库
标准的C++
由三个重要部分组成:
- 核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
- C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
- 标准模板库(STL),提供了大量的方法,用于操作数据结构等。
C++ 基本语法
C++
程序可以定义为对象的集合,这些对象通过调用彼此的方法进行交互。现在让我们简要地看一下什么是类、对象,方法、即时变量。
对象 - 对象具有状态和行为。例如:一只狗的状态 - 颜色、名称、品种,行为 - 摇动、叫唤、吃。对象是类的实例。
类 - 类可以定义为描述对象行为/状态的模板/蓝图。
方法 - 从基本上说,一个方法表示一种行为。一个类可以包含多个方法。可以在方法中写入逻辑、操作数据以及执行所有的动作。
即时变量 - 每个对象都有其独特的即时变量。对象的状态是由这些即时变量的值创建的。
C++ 标识符
C++
标识符是用来标识变量、函数、类、模块,或任何其他用户自定义项目的名称。
一个标识符以字母A-Z
或 a-z
或下划线 _
开始,后跟零个或多个字母、下划线和数字(0-9)。
C++
标识符内不允许出现标点字符,比如@
、&
和%
。C++
是区分大小写的编程语言。
C/C++可以使用带有$
的标识符:
#include "stdio.h"
int main(){
int _2a$=0x99;
printf("%d\n",_2a$);
return 0;
}
$
可以放在前面:
#include "stdio.h"
int main(){
int $a=0x99;
printf("%d\n",$a);
return 0;
}
甚至是:
#include "stdio.h"
int main(){
int $8=0x99;
printf("%d\n", $8);
return 0;
}
三字符组
三字符组就是用于表示另一个字符的三个字符序列,又称为三字符序列。三字符序列总是以两个问号开头。
三字符序列不太常见,但 C++ 标准允许把某些字符指定为三字符序列。以前为了表示键盘上没有的字符,这是必不可少的一种方法。
三字符序列可以出现在任何地方,包括字符串、字符序列、注释和预处理指令。
下面列出了最常用的三字符序列:
三字符组 | 替换 |
---|---|
??= | # |
??/ | \ |
??’ | ^ |
??( | [ |
??) | ] |
??! | |
??< | { |
??> | } |
??- | ~ |
如果希望在源程序中有两个连续的问号,且不希望被预处理器替换,这种情况出现在字符常量、字符串字面值或者是程序注释中,可选办法是用字符串的自动连接:"...?""?..."
或者转义序列:"...?\?..."
。
从Microsoft Visual C++ 2010版开始,该编译器默认不再自动替换三字符组。如果需要使用三字符组替换(如为了兼容古老的软件代码),需要设置编译器命令行选项/Zc:trigraphs
g++仍默认支持三字符组,但会给出编译警告。
嵌套注释
块注释符(/*...*/
)是不可以嵌套使用的。但可以在一种注释内嵌套另一种注释。
/* 用于输出 Hello World 的注释
cout << "Hello World"; // 输出 Hello World
*/
此外,我们还可以使用·#if 0 ... #endif
来实现注释,且可以实现嵌套,格式为:
#if 0
code
#endif
也可以把#if 0
改成 #if 1
来执行 code
的代码。
这种形式对程序调试也可以帮助,测试时使用 #if 1
来执行测试代码,发布后使用 #if 0
来屏蔽测试代码。
#if
后可以是任意的条件语句。
下面的代码如果 condition
条件为true
执行 code1
,否则执行 code2
。
#if condition
code1
#else
code2
#endif
C++ 数据类型
变量的大小会根据编译器和所使用的电脑而有所不同。
下面实例会输出电脑上各种数据类型的大小。
#include<iostream>
#include<string>
#include <limits>
using namespace std;
int main()
{
cout << "type: \t\t" << "************size**************"<< endl;
cout << "bool: \t\t" << "所占字节数:" << sizeof(bool);
cout << "\t最大值:" << (numeric_limits<bool>::max)();
cout << "\t\t最小值:" << (numeric_limits<bool>::min)() << endl;
cout << "char: \t\t" << "所占字节数:" << sizeof(char);
cout << "\t最大值:" << (numeric_limits<char>::max)();
cout << "\t\t最小值:" << (numeric_limits<char>::min)() << endl;
cout << "signed char: \t" << "所占字节数:" << sizeof(signed char);
cout << "\t最大值:" << (numeric_limits<signed char>::max)();
cout << "\t\t最小值:" << (numeric_limits<signed char>::min)() << endl;
cout << "unsigned char: \t" << "所占字节数:" << sizeof(unsigned char);
cout << "\t最大值:" << (numeric_limits<unsigned char>::max)();
cout << "\t\t最小值:" << (numeric_limits<unsigned char>::min)() << endl;
cout << "wchar_t: \t" << "所占字节数:" << sizeof(wchar_t);
cout << "\t最大值:" << (numeric_limits<wchar_t>::max)();
cout << "\t\t最小值:" << (numeric_limits<wchar_t>::min)() << endl;
cout << "short: \t\t" << "所占字节数:" << sizeof(short);
cout << "\t最大值:" << (numeric_limits<short>::max)();
cout << "\t\t最小值:" << (numeric_limits<short>::min)() << endl;
cout << "int: \t\t" << "所占字节数:" << sizeof(int);
cout << "\t最大值:" << (numeric_limits<int>::max)();
cout << "\t最小值:" << (numeric_limits<int>::min)() << endl;
cout << "unsigned: \t" << "所占字节数:" << sizeof(unsigned);
cout << "\t最大值:" << (numeric_limits<unsigned>::max)();
cout << "\t最小值:" << (numeric_limits<unsigned>::min)() << endl;
cout << "long: \t\t" << "所占字节数:" << sizeof(long);
cout << "\t最大值:" << (numeric_limits<long>::max)();
cout << "\t最小值:" << (numeric_limits<long>::min)() << endl;
cout << "unsigned long: \t" << "所占字节数:" << sizeof(unsigned long);
cout << "\t最大值:" << (numeric_limits<unsigned long>::max)();
cout << "\t最小值:" << (numeric_limits<unsigned long>::min)() << endl;
cout << "double: \t" << "所占字节数:" << sizeof(double);
cout << "\t最大值:" << (numeric_limits<double>::max)();
cout << "\t最小值:" << (numeric_limits<double>::min)() << endl;
cout << "long double: \t" << "所占字节数:" << sizeof(long double);
cout << "\t最大值:" << (numeric_limits<long double>::max)();
cout << "\t最小值:" << (numeric_limits<long double>::min)() << endl;
cout << "float: \t\t" << "所占字节数:" << sizeof(float);
cout << "\t最大值:" << (numeric_limits<float>::max)();
cout << "\t最小值:" << (numeric_limits<float>::min)() << endl;
cout << "size_t: \t" << "所占字节数:" << sizeof(size_t);
cout << "\t最大值:" << (numeric_limits<size_t>::max)();
cout << "\t最小值:" << (numeric_limits<size_t>::min)() << endl;
cout << "string: \t" << "所占字节数:" << sizeof(string) << endl;
// << "\t最大值:" << (numeric_limits<string>::max)() << "\t最小值:" << (numeric_limits<string>::min)() << endl;
cout << "type: \t\t" << "************size**************"<< endl;
return 0;
}
本实例使用了 endl
,这将在每一行后插入一个换行符,<< 运算符用于向屏幕传多个值。我们也使用 sizeof()
函数来获取各种数据类型的大小。
当上面的代码被编译和执行时,它会产生以下的结果,结果会根据所使用的计算机而有所不同:
type: ************size**************
bool: 所占字节数:1 最大值:1 最小值:0
char: 所占字节数:1 最大值: 最小值:?
signed char: 所占字节数:1 最大值: 最小值:?
unsigned char: 所占字节数:1 最大值:? 最小值:
wchar_t: 所占字节数:4 最大值:2147483647 最小值:-2147483648
short: 所占字节数:2 最大值:32767 最小值:-32768
int: 所占字节数:4 最大值:2147483647 最小值:-2147483648
unsigned: 所占字节数:4 最大值:4294967295 最小值:0
long: 所占字节数:8 最大值:9223372036854775807 最小值:-9223372036854775808
unsigned long: 所占字节数:8 最大值:18446744073709551615 最小值:0
double: 所占字节数:8 最大值:1.79769e+308 最小值:2.22507e-308
long double: 所占字节数:16 最大值:1.18973e+4932 最小值:3.3621e-4932
float: 所占字节数:4 最大值:3.40282e+38 最小值:1.17549e-38
size_t: 所占字节数:8 最大值:18446744073709551615 最小值:0
string: 所占字节数:24
type: ************size**************
typedef 声明
您可以使用 typedef
为一个已有的类型取一个新的名字。下面是使用typedef
定义一个新类型的语法:
typedef type newname;
例如,下面的语句会告诉编译器,feet
是 int
的另一个名称:
typedef int feet;
现在,下面的声明是完全合法的,它创建了一个整型变量 distance:
feet distance;
typedef
可以声明各种类型名,但不能用来定义变量。typedef
只是对已经存在的类型增加一个类型名,而没有创造新的类型。- 当在不同源文件中用到同一类型数据(尤其是像数组、指针、结构体、共用体等类型数据)时,常用
typedef
声明一些数据类型,把它们单独放在一个头文件中,然后在需要用到它们的文件中用#include
命令把它们包含进来,以提高编程效率。 - 使用
typedef
有利于程序的通用与移植。有时程序会依赖于硬件特性,用typedef
便于移植。比如定义一个叫FALSE
的浮点类型,在目标平台一上,让它表示最高精度的类型为:
typedef long double FALSE;
在不支持long double
的平台二上,改为:
typedef double FALSE;
在连 double
都不支持的平台三上,改为:
typedef float FALSE;
也就是说,当跨平台时,只要改下typedef
本身就行,不用对其他源码做任何修改。
标准库就广泛使用了这个技巧,比如 size_t
。
另外,因为 typedef
是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。
typedef 与 #define 的区别
1. 执行时间不同
关键字 typedef
在编译阶段有效,由于是在编译阶段,因此typedef
有类型检查的功能。
#define
则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字符串替换,而不进行任何检查。
typedef
会做相应的类型检查:
typedef unsigned int UINT;
void func()
{
UINT value = "abc"; // error C2440: 'initializing' : cannot convert from 'const char [4]' to 'UINT'
cout << value << endl;
}
#define
不做类型检查:
// #define用法例子:
#define f(x) x*x
int main()
{
int a=6, b=2, c;
c=f(a) / f(b);
printf("%d\n", c);
return 0;
}
程序的输出结果是: 36
,根本原因就在于 #define
只是简单的字符串替换。
2、功能有差异
typedef
用来定义类型的别名,定义与平台无关的数据类型,与struct
的结合使用等。
#define
不只是可以为类型取别名,还可以定义常量、变量、编译开关等。
3、作用域不同
#define
没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用。
而typedef
有自己的作用域。
#define
没有作用域的限制,只要是之前预定义过就可以
void func1()
{
#define HW "HelloWorld";
}
void func2()
{
string str = HW;
cout << str << endl;
}
而typedef
有自己的作用域
void func1()
{
typedef unsigned int UINT;
}
void func2()
{
UINT uValue = 5;//error C2065: 'UINT' : undeclared identifier
}
class A
{
typedef unsigned int UINT;
UINT valueA;
A() : valueA(0){}
};
class B
{
UINT valueB;
//error C2146: syntax error : missing ';' before identifier 'valueB'
//error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
};
上面例子在B
类中使用UINT
会出错,因为UINT
只在类A
的作用域中。此外,在类中用typedef
定义的类型别名还具有相应的访问权限
class A
{
typedef unsigned int UINT;
UINT valueA;
A() : valueA(0){}
};
void func3()
{
A::UINT i = 1;
// error C2248: 'A::UINT' : cannot access private typedef declared in class 'A'
}
而给UINT加上public
访问权限后,则可编译通过。
class A
{
public:
typedef unsigned int UINT;
UINT valueA;
A() : valueA(0){}
};
void func3()
{
A::UINT i = 1;
cout << i << endl;
}
对指针的操作
二者修饰指针类型时,作用不同。
typedef int * pint;
#define PINT int *
int i1 = 1, i2 = 2;
const pint p1 = &i1; //p不可更改,p指向的内容可以更改,相当于 int * const p;
const PINT p2 = &i2; //p可以更改,p指向的内容不能更改,相当于 const int *p;或 int const *p;
pint s1, s2; //s1和s2都是int型指针
PINT s3, s4; //相当于int * s3,s4;只有一个是指针。
void TestPointer()
{
cout << "p1:" << p1 << " *p1:" << *p1 << endl;
//p1 = &i2; //error C3892: 'p1' : you cannot assign to a variable that is const
*p1 = 5;
cout << "p1:" << p1 << " *p1:" << *p1 << endl;
cout << "p2:" << p2 << " *p2:" << *p2 << endl;
//*p2 = 10; //error C3892: 'p2' : you cannot assign to a variable that is const
p2 = &i1;
cout << "p2:" << p2 << " *p2:" << *p2 << endl;
}
结果:
p1:00EFD094 *p1:1
p1:00EFD094 *p1:5
p2:00EFD098 *p2:2
p2:00EFD094 *p2:5
枚举类型
枚举类型(enumeration
)是C++
中的一种派生数据类型,它是由用户定义的若干枚举常量的集合。
如果一个变量只有几种可能的值,可以定义为枚举(enumeration
)类型。所谓"枚举"是指将变量的值一一列举出来,变量的值只能在列举出来的值的范围内。
创建枚举,需要使用关键字 enum
。枚举类型的一般形式为:
enum 枚举名{
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数]
} 枚举变量;
如果枚举没有初始化, 即省掉"=整型常数"时, 则从第一个标识符开始。
例如,下面的代码定义了一个颜色枚举,变量c
的类型为color
。最后,c
被赋值为 “blue
”。
enum color
{
red, green, blue
} c;
c = blue;
默认情况下,第一个名称的值为 0,第二个名称的值为 1,第三个名称的值为 2,以此类推。但是,您也可以给名称赋予一个特殊的值,只需要添加一个初始值即可。例如,在下面的枚举中,green 的值为 5。
enum color
{
red, green=5, blue
};
在这里,blue 的值为 6,因为默认情况下,每个名称都会比它前面一个名称大 1,但 red 的值依然为 0。