一、第一个C++程序
1、编译器:g++,如果用gcc,需要带上-lstdc++,指定其使用标准C++的运行库。
2、源文件扩展名:.cpp/.cc/.C/.cxx/.c++,最好用.cpp,兼容性好。
3、头文件:#include ,大多数的标准库头文件都没有.h后缀,在/usr/include/c++目录下。
4、输出:cout —— 标准输出对象
输入:cin —— 标准输入对象
插入运算符:<<
提取运算符:>>
5、std:所有标准库的函数、对象、类型都位于std名字空间中。
#include <iostream>
int main(){
std::cout << "Hello,world!" << std::endl;
int i;
double d;
char s[256];
//scanf("%d%lf%s",&i,&d,s);
std::cin >> i >> d >> s;
//printf("%d %lf %s\n", i, d, s);
std::cout << i << ' ' << d << ' ' << s << '\n';
return 0;
}
二、名字空间
名字空间用来对程序中的标识符(类型、函数、变量)按照某种逻辑规则划分成若干组。
2.1 定义名字空间
namespace 名字空间名{
名字空间成员;
}
2.2 使用名字空间
(1)作用域限定符:名字空间名::名字空间成员,表示访问特定名字空间中的特定成员。
(2)名字空间指令:using namespace 名字空间名;
在该条指令之后的代码对指令所指的名字空间中的所有成员都可见。可直接访问这些成员,无需加“::”。
(3)名字空间声明:using 名字空间名::名字空间成员;
将指定名字空间中的某个成员引入当前作用域,可直接访问这些成员,无需加“::”。
(4)匿名名字空间
如果一个标识符没有被显示地定义在任何名字空间中,编译器会将其缺省地置于匿名名字空间中。对匿名名字空间中的成员通过“::名字空间成员”的形式访问。
(5)名字空间合并
(6)名字空间嵌套
namespace ns1{
namespace ns2{
namespace ns3{
void foo(){ ... };
}
}
}
ns1::ns2::ns3::foo();
using namespace ns1::ns2::ns3;
foo();
#include <iostream>
using namespace std;
//namespace{
void print(int money){
cout << money << endl;
}
//}
//农行名字空间
namespace abc{
int balance=0;
void save(int money){
balance += money;
}
void draw(int money){
balance -= money;
}
}
namespace abc{
void salary(int money){
balance += money;
}
void print(int money){
cout << "农行:";
::print(money);//访问匿名名字空间中的
}
}
//建行名字空间
namespace ccb{
int balance = 0;
void save(int money){
balance += money;
}
void draw(int money){
balance -= money;
}
void salary(int money){
balance += money;
}
}
int main(){
using namespace abc;//名字空间指令
save(5000);
cout << "农行:" << balance << endl;
draw(3000);
cout << "农行:" << balance << endl;
ccb::save(8000);
cout << "建行:" << ccb::balance << endl;
ccb::draw(5000);
cout << "建行:" << ccb::balance << endl;
using ccb::salary;//名字空间声明
salary(6000);
cout << "建行:" << ccb::balance << endl;
abc::print(balance);
return 0;
}
三、C++中的结构体、联合和枚举
3.1 C++中的结构体
(1)定义结构体型变量时,可以省略struct关键字。
(2)结构体内部可以定义函数——成员函数。
(3)sizeof(空结构)—— 1。
//struct.c
/*用gcc编译器编译出来的结果是sizeof(struct A) = 0,sizeof(a) = 0,0xbf814a87,但如果用g++的编译器,则结果大小都为1.
*/
#include <stdio.h>
int main(){
struct A{};
printf("sizeof(struct A) = %d\n",sizeof(struct A));
struct A a;
printf("sizeof(a) = %d\n", sizeof(a));
struct A* pa = &a;
printf("%p\n",pa);
}
//struct.cpp
#include <iostream>
using namespace std;
struct Student{
char name[128];
int age;
void who(){
cout << "我叫" << name << ",今年" << age << "岁了。" << endl;
}
};
int main(){
Student student = {"张飞", 25}, *ps = &student;
student.who();
ps->who();
struct A{};
cout << sizeof(A) << endl;
return 0;
}
3.2 C++中的联合
增加了匿名联合的概念。借用联合语法的形式,描述一些变量在内存中的布局方式。
#include <iostream>
using namespace std;
int main(){
//匿名联合
union{
int x;
char c[4]/* = {'A', 'B', 'C', 'D'}*/;
};
cout << (void*)&x << ' ' << (void*)c << endl;
x = 0x12345678;
for (int i = 0;i < 4;++i){
cout << hex << (int)c[i] << ' ';
}
cout << endl;
return 0;
}
/*
联合体union的存放顺序是所有成员都从低地址开始存放。小端模式是低字节存放在低地址,高字节存放在高地址;大端模式是高字节存放在低地址,低字节
存放在高地址。可以这么看,内存地址从低到高,小端模式就是顺时针旋转,大端模式就是逆时针旋转。
*/
3.3 C++中的枚举
C++中的枚举是一个独立的数据类型。
C:
enum E {a, b, c};
enum E e;
e = a;
e = 1000;
C++:
enum E {a, b, c};
E e;
e = a;
e = b;
e = c;
e = 1000;//ERROR!
e = 1;//ERROR!
#include <iostream>
using namespace std;
int main(){
enum E {a, b, c};
E e;
e = a;
e = b;
e = c;
//e = 1000;
//e = 1;
return 0;
}
四、C++的布尔类型
bool b = true;
b = false;
cout << sizeof(b) << endl;//1
b = 100;
b = 1.234;
b = "hello";
b = 'A';
#include <iostream>
using namespace std;
int main(){
bool b = true;
cout << sizeof(b) << endl;
cout << b << endl;
b = false;
cout << b << endl;
b = 3.14;
cout << b << endl;
char* p = NULL;
b = p;
cout << b << endl;
cout << boolalpha << b <<endl;
return 0;
}
/*运行后的结果:
1
1
0
1
0
false
*/
五、C++中的运算符别名
C++中的运算符,可以用其他关键字转换,以下列出部分常用运算符的转换。
&& —— and
|| —— or
& —— bitand
| —— bitor
^ —— xor
{ —— <%
} —— %>
[ —— <:
] —— :>
六、C++中的函数
6.1 重载
在同一个作用域中,函数名相同,参数表不同的函数,构成重载函数关系。
C++编译器会对程序中的函数做换名,将参数表中的类型信息汇合到函数名中,以保证函数名的唯一。通过extern “C”,可以要求编译器不做C++换名,以方便在C语言的模块中使用C++编译生成的代码。
nm:linux中的命令,用于显示库文件或可执行文件的符号表。
#include <iostream>
using namespace std;
void foo(int a){
cout << "foo(int)" << endl;
}
void bar(int a){}
//int foo(int a){}
void foo(int a,double b){
cout << "foo(int,double)" << endl;
}
void foo(double a,int b){
cout << "foo(double,int)" << endl;
}
//int foo(int b,double a){}
int main(){
foo(100);
foo(100, 1.23);
foo(1.23, 100);
//foo(100, 100);
return 0;
}
#include <iostream>
using namespace std;
namespace ns1{
int foo(int a){
cout << "ns1::foo(int)" << endl;
return a;
}
};
namespace ns2{
double foo(double a){
cout << "ns2::foo(double)" << endl;
return a;
}
};
int main(void){
using namespace ns1;
using namespace ns2;
cout << foo(10) << endl;
cout << foo(1.23) << endl;
using ns1::foo;
cout << foo(10) << endl;
cout << foo(1.23) << endl;
using ns2::foo;
cout << foo(10) << endl;
cout << foo(1.23) << endl;
return 0;
}
/*
运行结果:
ns1::foo(int)
10
ns2::foo(double)
1.23
ns1::foo(int)
10
ns1::foo(int)
1
ns1::foo(int)
10
ns2::foo(double)
1.23
*/
//math.cpp
//g++ -c math.cpp
extern "C" {
int add(int a,int b){
return a + b;
}
int sub(int a,int b){
return a - b;
}
}
//calc.c
//gcc calc.c math.o -lstdc++
#include <stdio.h>
int add(int,int);
int main(){
printf("%d\n",add(10,20));
return 0;
}
6.2 缺省参数和哑元参数
(1)如果调用一个函数时,没有提供实参,那么对应形参就取缺省值。
(2)如果一个参数带有缺省值,那么它后边的所有参数必须都带有缺省值。
(3)如果一个函数声明和定义分开,那么缺省参数只能放在声明中。
(4)避免和重载发生歧义。
(5)只有类型而没有名字的形参,谓之哑元。
#include <iostream>
using namespace std;
void foo(int a = 10, double b = 0.01, const char* c = "xxx");
void foo(){}
void bar(int){
cout << "bar(int)" << endl;
}
void bar(int, double){
cout << "bar(int,double)" << endl;
}
int main(){
foo(1, 3.14, "Hello");
foo(1, 3.14);
foo(1);
//foo();//歧义
bar(100);
bar(100, 1.23);
return 0;
}
void foo(int a/* = 10*/, double b /*= 0.01*/, const char* c/* = "xxx"*/){
cout << a << ' ' << b << ' ' << c << endl;
}
6.3 内联
(1)编译器用函数的二进制代码替换函数调用语句,减少函数调用的时间开销。这种优化策略称为内联。
(2)频繁调用的简单函数适合内联,而稀少调用的复杂函数不适合内联。
(3)递归函数无法内联。
(4)通过inline关键字,可以建议编译器对指定函数进行内联,但是仅仅是建议而已。inline void foo(int x,int y){ … }
#include <iostream>
using namespace std;
void testg(){
cout<<"hello"<<endl;
}
inline void testgg(){
cout<<"world"<<endl;
}
int main(){
testg();
testgg();
}