第一章 C到C++过度阶段
- 第一个C++程序:
- 使用`namespace+名字`
- using关键字
- `bool`类型
- string字符串
- 结构体struct
- 结构体成员函数指针的获取方式
- `const`关键字:
- 内联函数
- 函数缺省值:
- 函数重载:
- 引用(quote)
- 开辟空间
第一个C++程序:
//输入输出流,c++标准头里没有.h
#include <iostream>
//标准名字空间,避免同名多人协作开发标识符冲突的问题
using namespace std;
int main(int argc, char const *argv[])
{
int i;
cout << "Hello world!!!" << endl; //输出
cin >> i;//输入
return 0;
}
编译:
g++ hello.c //g++是gcc的提升,g++可以编译的,gcc有的不可
使用namespace+名字
namespace A{
int a=50;
void showInfo(){
cout <<"我在A中"<< endl;
}
//名字空间也可以互相嵌套
namespace B{
int a=200;
void showInfo(){
cout <<"我在A中的B中"<< endl;
}
}
}
namespace B{
int a=100;
void showInfo(){
cout <<"我在B中"<< endl;
}
}
int main(){
//使用::域名信息符,访问指定空间的变量和函数
//使用方式:名字空间::变量/函数
cout << A::a << endl;
cout << B::a << endl;
cout << A::B::a << endl;
A::showInfo();
B::showInfo();
A::B::showInfo();
return 0;
}
名字空间,相当于对全局作用域进行分隔。
using关键字
- using+具体某个域中的标识:指定具体导入
如:using std::cout; using std::endl;
using+namespace+名字空间
:指定某个空间全部导入如:using namespace std;
- 起别名 , 相当于typedef 的作用
如:using uint32=int;
bool
类型
只有两个值(1true、0false)
#include <iostream>
using namespace std;
int main()
{
bool ok;
ok = true;
cout << ok <<endl;
ok = false;
cout << ok << endl;
return 0;
}
string字符串
std::string
边界检查:str.at(110);//解决越界问题
#include <iostream>
using namespace std;
using std::string;
int main()
{
string str="yao";
// cout << str[100] << endl;//越界,不提示
// cout << str.at(100) << endl;//越界,提示错误
const char *c_str =str.c_str();//使用c指针访问字符串
cout << c_str << endl;//yao
cout << str.front() << endl;//字符串第一位API 即:y
cout << str.back() << endl;//字符串最后一位API 即:o
cout << str.length() << endl;//字符串的长度API 即:3
cout << str.size() << endl;//字符串的大小API(不同于c字符串,没有'\0') 即:3
string str1="liang";
cout << str+str1 << endl;//追加字符串
str+=str1;
cout << str << endl;//yaoliang
str.append(str1);//API追加字符串
cout << str << endl;//yaoliangliang
return 0;
}
结构体struct
- 可以定义函数,直接复制,不像c中声明
- 具有封装性,默认public,也可设置成private(私有的)
- class是
struct
衍生而来,默认是private
#include <iostream>
using namespace std;
struct stu{
public:
string name="yaoliang";
static int salary;
int age;
void write_code()
{
cout << "writing" << endl;
}
};
//结构体大小
//1.与非代码段和非静态区相关,函数在代码段(所以不计算),static修饰的变量在静态区(所以不计算)
//2.string 的大小为32,在64位系统,以8字节对齐
int main()
{
stu s;
s.age=18;
cout << s.age << endl;//18
cout << s.name << endl;//yaoliang
s.write_code();//write.ing
cout << sizeof(stu) << endl;//40 (字符串32位+int(8字节对齐))
return 0;
}
结构体成员函数指针的获取方式
&的扩展
#include <iostream>
using namespace std;
struct Stu{
string name;
int age;
void show_stuInfo(){
cout << "姓名:" << name << ",年龄:" << age << endl;
}
};
void show_Info(){
cout << "加油!!!" << endl;
}
int main()
{
int a=10;
int *p=&a;
cout << *p << endl;
int arr[3]={1,2,3};
int (*parr)[3]=&arr;
cout << **parr <<endl;
void (*func)()=show_Info;
func();
struct Stu s={"yaoliang",18};
s.show_stuInfo();
void (Stu::*func1)()=&Stu::show_stuInfo;//理解:指针访问结构体函数需要取地址
(s.*func1)();
return 0;
}
在c++中的作用域:全局作用域,局部作用域(包括语句块作用域),类域,名字空间作用域
const
关键字:
int a=100;
printf("%d\n",*p);
const int *p=&a;//指针可变,a值不能变
int const *p=&a;//指针可变,a值不能变
int * const p=&a;//指针不可变,a值可以改变
const int * const p=&a;//都不可改变
总结:const修饰指针,看*,*前+const,数值不变,*后+const,指针指向不变
#include <iostream>
using namespace std;
//所以在c++中,用下面这个
const int my_max = 1024;
//(在编译阶段替换,优于#define MAX 1024(在预处理阶段,不安全,error不好找))
int main()
{
const int a=10;
int *p=(int *)&a;
*p=500;
cout << " a = " << a << endl;//10
cout << " *p = " << *p << endl;//500
//原因:编译优化:const修饰的变量承接的是一个常量值,
//编译器在编译阶段,将自动把a当作一个常量
const int volatile b=20;//volatile 防止编译优化,可以随时改变
int *q=(int *)&b;
*q=200;
cout << " b = " << b << endl;
cout << " *q = " << *q << endl;
return 0;
}
内联函数
条件:不能耗时,不能循环,不能递归,代码精简(3不1精)
功能:解决C中宏函数的问题。
宏函数的优势:没有函数调用的过程,没有函数栈帧的开辟,没有函数的跳转
内联函数的作用:大大提高了程序的运行效率,但是也有代价的,最终可执行代码膨胀
#include <iostream>
using namespace std;
#define min_i(x,y) ((x)<=(y)?(x):(y))
#define min_t(type,x,y) ({type _x = x;type _y = y;_x<_y?_x:_y;})
#define min(x,y) ({\
const typeof(x) _x = (x);\
const typeof(y) _y = (y);\
_x<_y?_x:_y;\
})
//内联函数
inline int my_min(int x,int y){
return x<y?x:y;
}
int main()
{
int a = 10;
int b = 20;
cout << "min_i(a++,b++)=" << min_i(a++,b++) << endl;//11
cout << "a=" << a << endl;//12
cout << "b=" << b << endl;//21
a=10;
b=20;
cout << "min_t(int,a++,b++)=" << min_t(int,a++,b++) << endl;//10
cout << "a=" << a << endl;//11
cout << "b=" << b << endl;//21
a=10;
b=20;
cout << "min(int,a++,b++)=" << min(a++,b++) << endl;//10
cout << "a=" << a << endl;//11
cout << "b=" << b << endl;//21
a=10;
b=20;
cout << "my_min(a++,b++)=" << my_min(a++,b++) << endl;//10
cout << "a=" << a << endl;//11
cout << "b=" << b << endl;//21
}
define和inline
的区别:
- 内联函数在编译时展开,define在预处理阶段展开
- 内联函数直接嵌入到目标代码中,宏只做一个简单的文本替换
- 内联函数在编译阶段有类型检测,语法处理等功能,而宏没有
inline
是函数,宏不是
函数缺省值:
#include <iostream>
using namespace std;
int add(int a=2,int b=1){//从右往左依次赋值,不能跳跃,原因入栈先后顺序
return a+b;
}
int main()
{
int a=10,b=20;
cout << add(a,b) << endl;//结果为:30
cout << add(a) << endl;//结果为:11,采用缺省
cout << add() << endl;//结果为:3,采用缺省
return 0;
}
函数重载:
是函数调用的灵活实现,也是多态的一种(同名函数的不同实现《执行逻辑的不同》)。
底层机制:根据不同的**参数类型,参数个数不同,与返回值无关,函数名相同**,则会在底层的程序的代码段的符号表中生成一个新的函数名,当使用不同的实参调用时,寻找匹配的函数调用。
#include <iostream>
using namespace std;
int add(int a,int b){
return a+b;
}
float add(float a,float b){
return a+b;
}
string add(string a,string b){
return a+b;
}
//int add(int a,int b,int c=1){
// return a+b;
//}//与上面的int add(int a,int b)存在二义性,不能同时存在
int main()
{
cout << add(1,2) << endl;
cout << add(3.14f,5.12f) << endl;
cout << add("yao","liang") << endl;
return 0;
}
注意:使用缺省值,注意二义性
引用(quote)
出现原因:避免程序中出现野指针的现象,因为野指针在代码维护中,很难发现问题
底层实现:类型 * const 指针变量 = &变量
#include <iostream>
using namespace std;
int add(int * const a,int * const b){
return *a+*b;
}
int main()
{
int a=10,b=20;
cout << add(&a,&b) << endl;
return 0;
}
语法形式:类型名& 引用变量 = 某个变量
#include <iostream>
using namespace std;
int add(int * const a,int * const b){
return *a+*b;
}
int add(int& a,int& b){
return a+b;
}
int main()
{
int a=10,b=20;
cout << add(&a,&b) << endl;
cout << add(a,b) << endl;
cout << "a的地址:" << &a << endl;//0x4444
int * const c=&a;
cout << "c的地址:" << c << endl;//0x4444
int& c=a;//c没有自己的空间,相当于a的别名,相当于int * const &c = a;
cout << "c的地址:" << &c << endl;//0x4444
return 0;
}
引用优点:防止指针传址造成的不良影响,
注意:不要返回局部的返回值,引用作为函数返回值时,可以作为左值使用
#include <iostream>
using namespace std;
static int f = 100;
int& add(int& a,int& b){
f=a+b;
return f;
}
int main()
{
int a=10,b=20;
cout << add(a,b) << endl;//30
add(a,b)=1000;
cout << f << endl;//1000
return 0;
}
指针与引用的对比:
#include <stdio.h>
static int *fun;
int *func(int * const a,int * const b) {
int sum=*a+*b;
fun=∑
return fun;
}
int main(int argc, const char *argv[])
{
/*your code*/
int x=10,y=20;
printf("%d\n",*func(&x,&y));
*func(&x,&y)=100;
printf("%d\n",*fun);
return 0;
}
实例(数值交换):
#include <iostream>
using namespace std;
void swapfunc(int& a,int& b){
int temp=a;
a=b;
b=temp;
}
int main()
{
int x=10,y=20;
cout << "x = " << x << ",y = " << y << endl;//x=10,y=20
swapfunc(x,y);
cout << "x = " << x << ",y = " << y << endl;//x=20,y=10
return 0;
}
常引用:
#include <iostream>
using namespace std;
string func(const string & s){
// s="yao";
return s;
}
int main()
{
string str="yaoliang";
cout << "str = " << func(str) << endl;
return 0;
}
总结:
从编译器上:
- 引用是指针的升级
从语法形式上:
- 引用变量是引用空间的变量别名
- 引用引用的是一块合法的空间
- 指针可以是野指针,十分灵活,在c++中可能会把程序写飞
- 指针可以进行无限次的赋值
- 引用只能赋值一次
int * const a = &b; <==>int &a = b
开辟空间
在c中:
int *p=(int *)malloc(sizeof(*p));//申请空间,不初始化
memset(p,0,sizeof(*p));//初始化
升级:
int *q=(int *)calloc(0,sizeof(*q));//申请空间直接初始化
升级:
int *s=(int *)realloc(ptr,sizeof(int)*5);//给申请空间申请空间
realloc()函数将ptr所指向的内存块的大小更改为字节大小。内容将在区域的开始到新旧大小的最小值的范围内保持不变。如果新的大小大于旧的大小,则新增的内存将不会初始化。如果ptr为NULL,那么对于所有size值,调用等价于malloc(size);如果size等于零,且ptr不为NULL,则调用等价于free(ptr)。除非ptr为NULL,否则它一定是由之前对malloc()、calloc()或realloc()的调用返回的。如果指向的区域被移动,则执行free(ptr)操作。
failure:NULL;
在cpp
中:
#include <iostream>
using namespace std;
int main()
{
int *p=new int;//malloc
cout << *p << endl; //单纯开辟空间,未初始化
int *q=new int();//可在括号中指定初始化的值,calloc
cout << *q <<endl; //开辟空间,并初始化
int *a=new int[10]; //开辟连续的多个空间,不初始化
cout << *a << endl;
int *b=new int[10]();//开辟连续的多个空间,并初始化,但不可指定初始化值
cout << *b << endl;
int *c=new int[1000]{1,3};//开辟连续的多个空间,并指定初始化
for(int i=0;i<1000;i++){
cout << c[i] << " ";
}
cout << endl;
//释放资源
delete p;
delete q;
delete [] a;
delete [] b;
delete [] c;
return 0;
}
new是一个函数,里面调用了malloc()
;delete同,所以delete和delete[]功能相同,区别在于规范
failure:throw()抛出异常,bad_alloc()
注意:
-
在**内置函数**中,存在两步,申请与释放,所以delete与delete[]无区别,可以不规范
-
在**自定义函数**中,new不光是开辟空间,而且在开辟空间后会调用类中的构造函数,对类对象进行初始化
delete不光是回收空间,而是在回收空间前,先对类对象进行析构,所以**必须规范使用**
#include <iostream>
using namespace std;
struct stu{
string _name;
int _age;
//结构体或类中的构造函数
stu(string name ,int age){
_name=name;
_age=age;
cout << "含参构造" << endl;
}
//开辟多个空间
stu(){
cout << "无参构造" << endl;
}
//结构体或类的析构
~stu(){
cout << "析构" << endl;
}
};
int main()
{
stu* s=new stu("yaoliang",19);
delete s;
stu * ss=new stu[5];
delete[] ss;
return 0;
}