对象和常量
常对象。常对象指在任何场合都不能对其成员的值进行修改的对象。
定义常对象的形式为:
const类名 对象名(参数列表);
或者
类名 const 对象名(参数列表);
常数据成员。将对象的数据成员声明为const,则为常对象成员。
常对象成员只能在构造函数的初始化成员列表中对其进行初始化(参见初始化成员列表一节)。
常成员函数。常成员函数不能修改类中的成员数据。
常成员函数的声明形式为:返回类型 函数名() const。
如:
classCA
{
void Print() const;
};
voidCA::Print() const
{
cout<<"CallCA::Print()"<<endl;
};
常指针和指向常变量(或常对象)的指针
classCA;
voidFunc(const CA *pa); //函数内部不能通过pa修改对象的成员
voidmain()
{
int i=1;
int * const pi1=&i; //指针本身值不能改变
const int *pi2; //不能通过指针修改指向的整型变量值
CA * const pa1; //pa1本身的值不能变,没有赋初值,编译通不过
const CA *pa2; //不能通过pa2指针修改指向的对象的成员的值。
}
类的静态成员
在面向过程程序设计中,数绝共享主要是通过全局变量来实现的,虽然全局变量引入能够实现数据共享,但是使得变量的值贬得难以跟踪和调试。在面向过陈哥程序设计中,虽然提倡数据的封装和信息隐藏,但有时候也需要在对象间实现数据的共享。类的静态成员变量的引入使得这一目的得以实现。
静态数据成员为类的所有对象共享。即在内存中只有一份空间,静态数据成员的生存期为整个程序运行期。静态数据成员必须在类体外进行初始化。静态成员的通常用 类名::静态成员名 的形式访问
类的另外一种静态成员就是静态成员函数,静态成员函数的引入是为了访问类的成员变量,而且只能访问类的静态数据成员。静态成员的通常用 类名::静态成员函数名的形式调用。
例6、演示静态成员的用法
classCA
{
public:
int m_iNormal;
static int m_iStatic;
void NormalFunc()
{
m_iStatic++; //普通成员函数可以访问类的静态成员变量。思考:为什么还要引入静态成员函数访问静态成员变量
m_iNormal++;
}
static void StaticFunc()
{
m_iStatic++;
//m_iNormal++; //非法
}
//通过静态成员函数访问某个对象的普通数据成员s
static void StaticAccessNormal(CA *pThis)
{
pThis->m_iNormal++;
}
};
intCA::m_iStatic=100;
voidmain()
{
CA a,b;
CA::m_iStatic=200; //常用形式
a.m_iStatic=300; //不常用
b.m_iStatic=400; //不常用
CA::StaticFunc(); //常用形式
a.StaticFunc(); //不常用
b.StaticFunc(); //不常用
b.StaticAccessNormal(&a); //不常用
CA::StaticAccessNormal(&a);//常用形式
}
注意:静态成员函数没有this指针。
友元
前面章节讲过,当把一个的成员的访问属性设置成为非公有属性后,是不能从类的外部访问的。但是有的时候,我们需要某个函数或者类也能够访问这些非公有成员。
在C++中有这样的机制使得这一愿望得以实现,这就是友元机制。有以下三种友元:
友元函数 如果希望一个普通函数Func中能够访问类CTest中的非公有成员,可以在类CTest中声明普通函数Func为该类CTest的友元。即Func是类CTest的友元函数。
友元成员函数 如果希望类CTest2的成员函数CTest2Func可以访问类CTest1的非公有成员,可以在类CTest1中将类CTest2的成员函数CTest2Func声明为友元。
友元类 如果希望类CTest2的所有成员函数都可以访问类CTest1的非公有成员,可以在类CTest1中将整个类CTest2声明为友元。
注意:友元关系是单向、非传递的。
例7、演示友元的用法
#include<iostream>
usingnamespace std;
classCMyTime;
classCTest2
{
void Display(CMyTime &tm);
};
classCTest
{
public:
void Display(CMyTime &tm);
void Display2(CMyTime &tm);
friend class CTest2; //声明CTest2为CTest的友元
};
classCMyTime
{
private:
int m_iHour,m_iMinute,m_iSecond;
public:
CMyTime():m_iHour(14),m_iMinute(20),m_iSecond(1){}
friend void Display(CMyTime &tm); //声明Display为CMyTime的友元
friend void CTest::Display(CMyTime&tm);//声明CTest的成员函数Display为CMyTime的友元
friend class CTest; //声明CTest为CMyTime的友元
friend class CTest2; //因为友元关系不能传递,所以要在CTest2中访问CMyTime类的非公有成员,必须要声明CTest2为CMyTime的友元
};
voidDisplay(CMyTime &tm)
{
CMyTime obj;
obj.m_iHour=9; //普通函数访问对象的非公有成员
cout<<tm.m_iHour<<":"<<tm.m_iMinute<<":"<<tm.m_iSecond<<endl;
}
voidCTest::Display(CMyTime &tm)
{
cout<<tm.m_iHour<<":"<<tm.m_iMinute<<":"<<tm.m_iSecond<<endl;//别的类成员函数访问当前类的非公有成员
}
voidCTest::Display2(CMyTime &tm)
{
cout<<tm.m_iHour<<":"<<tm.m_iMinute<<":"<<tm.m_iSecond<<endl;
}
voidCTest2::Display(CMyTime &tm)
{
cout<<tm.m_iHour<<":"<<tm.m_iMinute<<":"<<tm.m_iSecond<<endl;
}
voidmain()
{
CMyTime time;
Display(time);
CTest test;
test.Display(time);
}
抽象类
当一个类的构造函数是私有或者保护型的时候,这样的类不能像普通类一样来实例化对象。这样的类叫做作抽象类。
构造函数是私有的情况,由于不能从外面调用该类的构造函数。我们考虑从内部来调用该类的构造函数来实例化该类的对象,具体方法是提供一个静态成员函数来调用该类的构造函数。
例8、定义一个类,使用该类只能实例化一个对象,我们把这种情况叫做单例。
#include<stdio.h>
classSingleton
{
public:
static Singleton* CreateInstance();
static void ReleaseInstance(Singleton*);
private:
Singleton(){};
static Singleton* pinstance;
};
//初始化成员指针
Singleton*Singleton::pinstance = 0;
Singleton*Singleton::CreateInstance()
{
if (pinstance == 0)
{
pinstance = new Singleton;
}
return pinstance;
}
voidSingleton::ReleaseInstance(Singleton *pThis)
{
delete pThis;
}
intmain()
{
Singleton *pObj=NULL;
// 调用静态成员函数实例化该类对象
pObj=Singleton::CreateInstance();
// 使用完毕后释放该类对象
Singleton::ReleaseInstance(pObj);
return 0;
}