Day 5知识点:
1.const 修饰数据成员的时候,初始化只能在参数列表中,被const修饰的数据成员不能被修改。
2.const 修饰成员函数时,位置在函数声明之后,函数体之前,要求在声明和定义处都要求const。const函数承诺不会修改数据成员,能访问const和非const数据成员,但不能修改非const数据成员,只能访问const成员函数(成员函数也不可修改数据成员)。
3.const 修饰类对象,是从对象的层面,不修改数据成员。只能调用const成员函数。非const成员对象,优先调用非const成员函数,若无,则可调用const成员函数。
4.static
用在全局变量中:可控制其外延性,限定其作用域,使其只能用于本文件;
用在局部变量中:控制其生命周期与存储位置。
作用在类内部:
a) 作用在数据成员上,用来实现族类对象间的数据共享;在生成对象的时候,普通数据成员才有空间。而static成员在类声明的时候就已经开辟了空间。
初始化。类内定义,类外初始化。type 类名::变量名 = 初值。
示例:
#include <iostream>
using namespace std;
class A
{
public:
int x;int y;
static int share;
};
int A::share = 0;
int main()
{
A a,b,c;
cout<<"sizeof(A) = "<<sizeof(A)<<endl;
cout<<"sizeof(a) = "<<sizeof(a)<<endl;
cout<<"sizeof(b) = "<<sizeof(b)<<endl;
cout<<"sizeof(c) = "<<sizeof(c)<<endl;
return 0;
}
b)作用在函数上。作用只有一个,用于管理static成员。Static修饰的成员函数,因为他属于类,所以没有this指针,不能访问非static数据成员及其成员函数。
示例:
#include <iostream>
using namespace std;
class School
{
public:
string& getTower()
{
return tower;
}
static string& getLib()
{
return lib; //没有指针,只能访问static数据成员
}
private:
string tower;
string lake;
static string lib;
};
string School::lib = "";
int main()
{
School::getLib() = "aa";
School::getLib()+="+bb";
School cz,bn,bs;
cz.getTower() = "boyata";
bn.getTower() = "shuita";
bs.getTower() = "wajueta";
cz.getLib() += "+cz";
bn.getLib() += "+bn";
bs.getLib() += "+bs";
cout<<cz.getLib()<<endl;
return 0;
}
例1.渲染树的创建
#include <iostream>
using namespace std;
class CCSprite
{
public:
CCSprite(int d)
{
data = d;
this->next = head;
head = this;
}
static void traverseCCSpirate()
{
CCSprite* ph = head;
while(ph != NULL)
{
cout<<ph->data<<endl;
ph = ph->next;
}
}
private:
int data;
CCSprite* next;
static CCSprite* head;
};
CCSprite* CCSprite::head = NULL;
int main()
{
new CCSprite(1);
new CCSprite(2);
new CCSprite(3);
CCSprite::traverseCCSpirate();
return 0;
}
5.static const数据成员在定义处直接初始化。
6.指向类成员的指针
1)指向类(非对象)数据成员的指针.
定义与初始化 :
//数据类型 类名::*指针名 = 类名::非静态数据成员
int Stu::*pa = &Stu::age; //从类的起始地址的偏移量
解引用:
s1.*pa; //类对象名.*指向非静态数据成员的指针
ps->*pa; //类对象指针->*指向非静态数据成员的指针
2)指向类(非对象)成员函数的指针.
定义与初始化 :
//数据类型(类名::*函数指针名)(参数列表) = &类名::非静态成员函数
void(Stu::*pf)()=&Stu::print;
解引用:
(s1.*pf)(); //注意,括号一定要全括
#include <iostream>
using namespace std;
class Stu
{
public:
Stu(string sn,int ia):
name(sn),age(ia){}
void print()
{
cout<<name<<"--"<<age<<endl;
}
public:
string name;
int age;
};
int main()
{
Stu s1("zhaosi",39);
Stu s2("aobaniu",79);
Stu* pp = new Stu("dadadadadada",80);
Stu *ps = &s1;
ps->print();
int *p = &s1.age;
int Stu::*pa = &Stu::age;
cout<<s1.age<<s2.age<<endl;
cout<<s1.*pa<<s2.*pa<<endl;
cout<<ps->*pa<<endl;
void(Stu::*pf)() = &Stu::print;
(s1.*pf)();
cout<<pp->*pa<<endl;
(pp->*pf)();
return 0;
}
例3.指向类成员函数的指针
#include <iostream>
using namespace std;
class Widget
{
public:
Widget()
{
pa[0] = &f;
pa[1] = &g;
pa[2] = &i;
pa[3] = &j;
}
void select(int idx)
{
(this->*pa[idx])(); //w.select(2)的时候调用select成员函数时,为什么不能默认w的this指针
//指向*pa[2]()而要加上this指针呢,*pa[2]的结果不是类内的成员函数吗。
//或者是因为对象的成员函数代表的是类成员而非对象,所以类成员函数指针记录
//的也只是”偏移量”?
}
private:
void f(){cout<<"void f()"<<endl;}
void g(){cout<<"void g()"<<endl;}
void i(){cout<<"void i()"<<endl;}
void j(){cout<<"void j()"<<endl;}
void(Widget::*pa[4])()={f,g,i,j}; //pa是个数组,数组里面都是指针,指针指向的是类成员函数而非对象
//的成员函数?所以*pa[idx]的值得到的是个地址偏移量,在select
//中要加上this,若用默认this,则结果*pa[idx]()等价于
//this->*pa[idx](),由于运算符优先级问题将会出现错误。所以需
//需要手动加上this,并加括号(this->*pa[idx])()
};
int main()
{
Widget w;
w.select(2);
return 0;
}
3)前向声明只能用于定义指向这个类型的指针或引用。
classA; //若将B进行声明而A的定义在B的定义之前的话在A中友元声明中
//的B作用域编译将会出现未定义;因为前向声明不能用于作用域声明
classB
{
public:
B(){}
void dis(A&other); //函数体不能再此处,如果在此处编译时由于A的成员x,y,z未定义会出现错误
};
classA
{
public:
A(){}
friend void B::dis(A&other);
private:
int x;
int y;
int z;
};
void B::dis(A& other)
{
cout<<other.x<<other.y<<other.z<<endl;
}