1.1static
修饰局部变量,延长生命周期(由栈区 --->静态区)
修饰全局变量或函数,限制作用域,只能用于本文件中使用
static+成员变量:
1.static成员变量不占class的空间
⒉.修饰成员变量,需要在外部单独定义(要加来源 A::val)
3.多个对象访问到的static变量是同一个(可以实现对象建间的通讯)
4.不用对象,也可以访问成员变量(要加来源 A::val)
static+成员函数:
1.成员函数不拥有this指针,不能访问普通成员变量,可以访问静态成员变量
2.不用对象,也可以访问成员函数(要加来源 A::print_val)
#include <iostream>
using namespace std;
class A
{
public:
void set_val(int n)
{
val=n;
}
static void print_val()//不拥有this指针,不能访问普通成员变量,可以访问静态成员变量
{
//this static修饰的成员函数不拥有this指针
//cout << x << endl; //static修饰的成员函数,不能访问普通成员变量
cout << val << endl; //static修饰的成员函数, 可以访问静态成员变量
}
public:
//private:
static int val;//1.
int x;
int y;
};
int A::val=10;//2.外部初始化之后才能赋值 权限public
int main()
{
A::print_val();
A a,a1,a2;
//1.static成员变量不占内存空间
//cout << sizeof(a) << endl;
//2. static修饰的变量,需要在类的外部单独定义
a.print_val();
a.set_val(100);
a.print_val();
//3.多个对象访问到的static变量是同一个 权限public
cout << &a.val <<endl;
cout << &a1.val <<endl;
cout << &a2.val <<endl;
//4.static修饰的public变量可以直接访问,不需要通过变量 权限public
cout << A::val << endl;
//cout << A::x << endl;没有static修饰的变量只能通过变量访问
}
用处(原理:多个对象访问到的static变量是同一个(可以实现对象建间的通讯))
1.对象间通讯
2.QT的文件对话框
3.计算对象的数量
1.2const
const+变量:表示变量为只读变量
1.变量不能被修改
2.定义变量时要初始化,不然会报错
const+指针
原则是:const修饰谁,谁的内容就不可变,其他的可变
1.coust int *p
const 和int 可以互换位置,二者是等价的。
当把const放最前面的时候,它修饰的就是*p,那么*p就不可变。
这种用法常见于定义函数的形参。前面学习printf 和 scanf,以及后面将要学习的很多函数,它们的原型中很多参数都是用const修饰的,这样做的好处是安全!我们通过参数传递数据时,就把数据暴露了。而大多数情况下只是想使用传过来的数据,并不想改变它的值,但往往由于编程人员个人水平的原因会不小心改变它的值。这时我们在形参中用const 把传过来的数据定义成只读的,这样就更安全了。这也是 const最有用之处。
所以如果你不想改变某个参数传过来的值,那么定义函数时就最好用const修饰这个参数,否则就不要用const修饰了。
特别要注意的是:
虽然在*p前加上 const可以禁止指针变量p 修改变量a 中的值,但是它只能“禁止指针变量p 修改”。
也就是说,它只能保证在使用指针变量p 时,p 不能修改a 中的值。
其他指向 a的没有用const修饰的指针变量照样可以修改a 的值,而且变量a自己也可以修改自己的值。
2.int *const p;
3.const int *const p;
const+结构体变量:
不能通过结构体变量修改结构体成员的值 a.set_val(10);//错的
不能给结构体变量进行赋值 a1=a2;//错的
const+结构体指针
const Data *p不能通过指针修改指针指向的空间 *p->set_val(10);//错的
Data *const p 不能修改指针的指向 p=&a1;//错的
const+成员变量:成员变量不能被修改
注意:要给const成员变量赋初值
方法一:直接赋初值,很固话,永远是一个值,不太好用
const int val=0;
方法二:通过构造函数初始化列表,灵活一点
A(int n=0,int m=1):val(n),x(m) //构造函数
const int val; //私有变量
const int x;
const +成员函数:不能修改函数内部的成员变量
const加载{}前面
void set_val(int x) const //不能修改函数内部的成员变量,有影响
{
val=x;
}
const+对象
1.const+类+对象 必须先初始化,const A a;(A中要写构造函数)
2.不能通过成员函数修改
3.使用的成员函数也要是const修饰的
4.成员变量的权限修改成public,可以访问,但是不能修改
1.3友元
friend 指类的朋友,使用友元访问类的私有成员。
修饰普通函数--友元函数
friend void fun(A &obj);//声明友元函数
void fun(A &obj)//参数得是要调用的私有变量所属的类的对象
{
cout << obj.val <<endl;
}
注意:友元会破坏类的封装性,尽量少用
友元用于处理与多个对象之间的私有数据有关的问题
修饰类
类A 类B
//类B 是类A的朋友类,B就可以调用A中的私有变量
A中
friend class B;B中
void func(A &obj)
{
cout << obj.val << endl;
}
通过clsaaB 中的成员函数,通过A类的对象(形参),访问A中的私有数据
友元关系不具有传递性。例如,类A是类B的友元,类B是类C的友元,但并不表示类A是类c的友元。
友元关系不具有交换性。例如,类A是类B的友元,但类B不是类A的友元。
作业:
1.new delete和malloc free的区别
1.申请的内存所在位置
new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存.自由存储区不仅可以是堆,还可以是静态存储区,这都看operator new在哪里为对象分配内存。
2.返回类型安全性
new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。
3.内存分配失败时的返回值
new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。
4.是否需要指定内存大小
使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。
5.是否调用构造函数/析构函数
new/delete会调用对象的构造函数/析构函数以完成对象的构造/析构。而malloc则不会。
6.对数组的处理
new对数组的支持体现在它会分别调用构造函数函数初始化每一个数组元素,释放对象时为每个对象调用析构函数。注意delete[]要与new[]配套使用,不然会找出数组对象部分释放的现象,造成内存泄漏
7.new与malloc是否可以相互调用
operator new /operator delete的实现可以基于malloc,而malloc的实现不可以去调用new。
8.是否可以被重载
opeartor new /operator delete可以被重载,而malloc/free并不允许重载
2.封装一种数据结构(链表、栈、队列、树)
链表
#include <iostream>
using namespace std;
typedef int data_t;
class LinkList
{
public:
LinkList * Create_Linklist() //创建链表
{
LinkList *head = new LinkList;
head->data=-1;
head->next=NULL;
cout << "链表创建成功" << endl;
return head;
}
int Linklist_Empty(LinkList *link) //判空
{
if(link->next==NULL)
return 1;
else
return 0;
}
int Linklist_Length(LinkList *link)//求链表长度
{
int len=0;
while(link->next!=NULL)
{
len++;
link=link->next;
}
return len;
}
void Linklist_Insert(LinkList *link,data_t data)//头插法
{
LinkList *s = new LinkList;
s->data=data;
s->next=link->next; //插入
link->next=s;
}
void Linklist_Insert_Pos(LinkList *link,int pos,data_t data)//按位置插入
{
int i=Linklist_Length(link);
if(pos<0 || pos>i+1) //判断pos是否合法
{
cout<< "pos erroe" << endl;
exit(-1);
}
for(i=0;i<pos+1;i++) //跳转到所要求的的位置
{
link=link->next;
}
LinkList *s = new LinkList; //插入
s->data=data;
s->next=link->next;
link->next=s;
}
void Linklist_Delete_Pos(LinkList *link,int pos)//按位置删除
{
if(Linklist_Empty(link))
{
cout<< "链表为空" << endl;
return ;
}
int i=Linklist_Length(link); //判断pos是否合法
if(pos<0 || pos>i+1)
{
cout<< "pos erroe" << endl;
exit(-1);
}
for(i=0;i<pos;i++) //跳转到所要求的的位置
{
link=link->next;
}
LinkList *s=link->next; //删除
cout <<"删除" <<s->data << endl; //打印删除的值
link->next=s->next;
delete s;
}
int Linklist_Find_Key(LinkList *link,data_t data)//按值查找
{
if(Linklist_Empty(link))
{
cout<< "链表为空" << endl;
return -1;
}
int i=-1,j=Linklist_Length(link);
while(link->data!=data && i++<j+1) //找到所求的的值,并记录次数
{
link=link->next;
}
if(i==j) //找完所有元素退出
{
cout << "表中无这个元素" <<endl;
return -1;
}
else //没找完所有元素
{
return i;
}
}
void Linklist_Delete_Key(LinkList *link,data_t data)//按值删除
{
if(Linklist_Empty(link))
{
cout<< "链表为空" << endl;
return ;
}
int i =Linklist_Find_Key(link,data);//找到值所在下表
Linklist_Delete_Pos(link,i); //根据下标删除
}
int Linklist_Find_Pos(LinkList *link,int pos)//按位置查找
{
if(Linklist_Empty(link))
{
cout<< "链表为空" << endl;
return -1;
}
int i=Linklist_Length(link);
if(pos<0 || pos>i+1) //判断pos是否合法
{
cout<< "pos erroe" << endl;
exit(-1);
}
for(i=0;i<pos+1;i++) //找到所求的位置
{
link=link->next;
}
cout<< link->data << endl;
}
void Linklist_Change_Key(LinkList *link,data_t data,data_t new_data)//按值改变值
{
int i=Linklist_Find_Key(link,data),j;//找到所求值的下标
for(j=0;j<=i;j++) //跳转到所求下标的节点
{
link=link->next;
}
link->data=new_data;
}
void Linklist_Setnull(LinkList *link)//清空表
{
LinkList *p=link->next;
while(p==NULL) //一个一个删
{
Linklist_Delete_Pos(link,0);
p=p->next;
}
link->next=NULL;
cout<<"链表以清空" <<endl;
}
void Linklist_free(LinkList *link)//删除表
{
if(link->next!=NULL)//判断是否只剩表头
{
Linklist_Setnull(link);
}
delete link;
}
void Linklist_Show(LinkList *link)//显示表中元素
{
if(Linklist_Empty(link)) //判空
{
cout <<"表中无元素" <<endl;
return;
}
while(link->next!=NULL)
{
link=link->next;
cout<<link->data <<" " ;
}
cout << endl;
}
void Linklist_Order(LinkList *link)//表逆序
{
LinkList *cur,*pre,*next;
cur=link->next;//cur指向第一个
next=cur->next;//next指向第二个
cur->next=NULL;//最后一个指向空
pre=cur; //pre指向前一个
cur=next; //cur指向当前
while(cur->next!=NULL)
{
next=cur->next;//next指向前一个
cur->next=pre;//链接后一个
pre=cur; //pre前移,为下次链接做准备
cur=next; //cur指向下一次要更改连接的目标
}
cur->next=pre;//最后一个链接上之前的
link->next=cur;//再把头指针指向更改后的第一个元素
Linklist_Show(link);
}
private:
data_t data;
LinkList *next;
};
int main(int argc, char *argv[])
{
int i,pos;
data_t data,new_data;
LinkList *head,*link;
link=head;//调用link,不改变head的值
while(1)
{
cout <<"\n\n\t\t\t欢迎使用链表\n\n";
cout <<"------------------------\n";
cout <<"\t\t1.创建链表 \n";
cout <<"\t\t2.插入元素(头插法) \n";
cout <<"\t\t3.按位置插入元素(后插) \n";
cout <<"\t\t4.删除元素(按序号) \n";
cout <<"\t\t5.删除元素(按值) \n";
cout <<"\t\t6.查询元素(按序号) \n";
cout <<"\t\t7.查询元素(按值) \n";
cout <<"\t\t8.更改元素(按值) \n";
cout <<"\t\t9.显示表中元素\n";
cout <<"\t\t10.置空表 \n";
cout <<"\t\t11.删除链表 \n";
cout <<"\t\t12.链表逆序 \n";
cout <<"\t\t0.退出 \n";
cout <<"请输入[0~10]\n";
cin >> i;
switch(i)
{
case 1:
{
head=link->Create_Linklist();
link=head;
break;
}
case 2:
{
cout <<"请输入要插入的值:\n";
cin >> data ;
link->Linklist_Insert(link,data);
break;
}
case 3:
{
cout <<"请输入要插入的位置与要插入的值(以空格隔开)\n";
cin >> pos >>data ;
link->Linklist_Insert_Pos(link,pos,data);
break;
}
case 4:
{
cout <<"请输入要删除的位置\n";
cin >> pos ;
link->Linklist_Delete_Pos(link,pos);
break;
}
case 5:
{
cout <<"请输入要删除的值\n";
cin >>data ;
link->Linklist_Delete_Key(link,data);
break;
}
case 6:
{
cout <<"请输入要查询的位置\n";
cin >>pos ;
link->Linklist_Find_Pos(link,pos);
break;
}
case 7:
{
cout <<"请输入要查找的值\n";
cin >> data ;
link->Linklist_Find_Key(link,data);
break;
}
case 8:
{
cout <<"请输入被替换的值与新值(以空格隔开)\n";
cin >>data >> new_data ;
link->Linklist_Change_Key(link,data,new_data);
break;
}
case 9:link->Linklist_Show(head);break;
case 10:link->Linklist_Setnull(link);break;
case 11:link->Linklist_free(head);break;
case 12:link->Linklist_Order(link);break;
case 0:exit(0);
}
}
return 0;
}