C++ 引用类型
引用类型:可以获得指针类型的效果,但是又可以避免指针可读性和可维护性差等问题。
1. 定义
<类型> &<引用变量>;
定义时要初始化
<类型>可以是除了void以外的任意C++类型。
如: int x=0; int &y=x;y=2;//此时x也是2
2. 引用类型 VS 指针类型
1)二者访问语法不同,指针是 *<指针变量> ,引用是<引用变量>
2)引用类型除了定义时指定的被引用变量外,不能再引用其他变量。
3)该变量没有自己的内存空间,而是与另一个变量共享同一个内存空间,也可以理解为引用类型变量是另一个变量的别名。
C++ 成员的访问控制
1. public
访问不受限制,在程序的任何地方都能访问一个类的public成员。
public成员是类与外界的一个接口。
2. private
默认的访问控制
只能在本类和友元中访问。
3. protected
只能在本类、派生类和友元中访问。
案例:
class A
{
int m,n;//private
public :
int x; //public
void f(); //public
private:
int z; //private
int h();//private
protected:
void g(); //protected
}
void A::f()
{
//....
}
C++ this指针
每一个成员函数(静态成员函数除外)都有一个this隐藏的指针类型的形参this,其类型为: <类型> *const this;
当能够区分各种成员时,可以不用使用this指针,否知可以通过使用this指针来区分。
class A
{
int x,y;
public:
void f();
void g(int x){
this->x = x;
}
}
C++ 构造函数
1. 定义
与类同名、无返回值类型的成员函数。
析构函数是对象创建的一部分,在创建对象时,会被自动调用;创建对象后,析构函数就不能再被调用
默认析构函数:不带参数,或者所有参数都有默认值的的析构函数,析构函数可以重载。
类的析构函数一般是公开的,但是有时也把析构函数声明为私有的(如单例模式中就把析构函数声明为私有的),其作用是限制创建该类对象的范围。
2. 调用
根据参数进行重载,决定调用哪个析构函数。
3. 成员初始化表
对于常量数据成员和引用数据成员(某些静态成员除外),不能在声明它们时进行初始化,也不能采用赋值操作对它们初始化。
class A
{
int x;
const int y=1;//Error
int &z=x;//Error
public:
A()
{
x=0;//OK
y=1;//Error,y是常量成员,其值不能改变
}
}
它们的初始化要在成员初始化表中进行。
class A
{
int x;
const int y;
int& z;
public:
A(): z(x),y(1)
{
x=0;
}
}
或者
class A
{
int x;
const int y;
int& z;
public:
A(): x(0),z(x),y(1)
{
}
}
C++ 析构函数
1. 定义
“~<类名>”
没有参数和返回值类型的成员函数。
2. 调用
当对象消亡时,在系统收回它所占的存储空间之前,它的析构函数会自动被调用。
一般清空下不需要定义析构函数,但是,如果对象在创建后申请了一些资源并且没有归还这些资源,就要定义析构函数在对象消亡前归还这些资源。
如果类中为提供析构函数,编译程序会在需要时隐式提供一个析构函数,该析构函数负责调用成员对象类和基类的析构函数。
class A()
{
char *str;
public:
A()
{
str=NULL;
}
A(const char *p)
{
str = new char(strlen(p)+1);
strcpy(str,p);
}
~A()
{
delete []str;
str = NULL;
}
}
当包含成员对象的对象消亡时,先调用本身类的析构函数,本身类的析构函数的函数体执行完毕后,再调用成员函数对象类的析构函数(在继承中,先调用和执行自己的析构函数,然后调用成员对象类的析构函数,最后调用基类的析构函数)。如果有多个成员对象,则成员对象析构函数的调用次序与它们定义的次序正好相反。
C++ 拷贝构造函数
1. 定义
<类名> (const <类名>&);
class A
{
int x,y;
public:
A();
A(const A& a)
{
x = a.x+1;
y = a.y+1;
}
}
其中,const是为了防止在函数中修改实参对象,可以省略。
拷贝构造函数也可以带有其他参数,但这些参数必须要有默认值。
2. 调用
下面三种情况将会调用拷贝构造函数:
1)定义对象
2)把对象作为值参数传递给函数
3)把对象作为返回值
如果在类定义中没有给出拷贝构造函数,则编译程序将会为其提供一个隐式的拷贝构造函数,此时的拷贝构造函数跟Java中的克隆函数有点像。
当类定义中包含成员对象,成员对象的拷贝初始化可由成员对象类的拷贝构造函数来实现。
系统提供的隐式拷贝构造函数会去调用成员对象的拷贝构造函数,而自定义的拷贝构造函数则不会自动去调用成员的拷贝构造函数,这时,必须要在拷贝构造函数的成员初始化表中显式指出。
class A
{
}
class B
{
int z;
A a;
public:
B();
B(const B& b): a(b.a)
{
z = b.z;
}
}
C++ 常成员函数
常常把对象的成员函数分为两类:修改对象状态的成员函数、获取对象状态的成员函数。
常成员函数就是一种获取对象状态的成员函数,并且不能改变对象的状态(也就是不能修改对象的成员的值)。
形式:
class A
{ ...
void f() const {...}
}
或
class A
{...
void f() const;//声明
}
void A::f() const //定义
{
...
}
当时要注意下面两个例子:
class A
{
int x;
char *p;
public:
...
void f() const
{
x=10; //Error
p = new char[20]; //Error
}
}
class A
{
int x;
char *p;
public:
...
void f() const
{
strcpy(p,"abc");//没有改变p的值,因此编译程序认为OK
*p = 'A';//同上
}
}
C++ 静态成员
在C++中,采用静态成员来解决同一个类的对象共享数据的问题。类的静态成员分为静态数据成员和静态成员函数。
1. 静态数据成员
静态数据成员在一个类中只分配一次存储空间,也就是一个类的所有对象的静态数据成员共享一块存储空间。
在计数时往往使用的就是静态数据成员。
2. 静态成员函数
静态成员函数只能访问静态成员(包括静态数据成员和静态成员函数),并且静态成员的访问也要遵循类的访问控制。
静态成员函数没有隐藏的this指针参数,因为静态成员函数对静态数据成员进行操作,而静态数据成员是某类对象共享的,它们只有一个拷贝,因此,静态成员函数不需要知道某个具体对象。