一.1,对象数组
我们定义普通类型的数组时
int a[100];
char b[100];
string s[100];
定义对象数组也是一样的
Student stud[5]; //定义stud数组,有5个元素
对象数组的初始化
Student::Student(int = 11, int = 8, int = 9);
Student stud[3] = {106, 5, 7}; //给每个对象提供第一个实参
Student stud[3] = {1, 2, 3, 4} //不合法的,实参个数超过对象数组元素个数
对每个数组的是三个参数都初始化
Student Stu[3] = { //定义对象数组。
Student(101, 1, 2); //调用第一个元素的构造函数,向它提供3个参数
Student(102, 3, 4); //调用第二个元素的构造函数,向它提供3个参数
Student(103, 5, 6); //调用第三个元素的构造函数,向它提供3个参数
}
注意:初始化每个对象时,直接用类名
一.2,对象指针
其实你定义一个 int a然后它在一个空间内,你可以用一个指针指向它(指针存放a的地址)这就指针。
对象指针给上述一样。定义一个指针变量存放对象的地址。
Time t; //定义t是Time类的对象
Time *pt; //定义pt为指向Time类对象的指针变量
pt = &t; //将t的起始地址赋给pt;
一般形式为:类名 *对象指针名
定义对象数据成员的指针变量一般形式为:
数据类型名 *指针变量名;
* pt; //pt所指向的对象t
(*pt).hour; //pt所指向对象中的hour成员,即t.hour
pt->hour; //pt所指向对象中的hour成员,即t.hour
(*pt).get_time(); //pt所指向对象中的get_time()函数,即t.get_time();
pt->get_time(); //pt所指向对象中的get_time()函数,即t.get_time();
2,3行等价。4,5行等价
一.3,指向对象成员的指针
指向对象数据成员的指针
int *p1; //定义指向整型的指针变量
p1 = &t1.hour; //将对象t1的数据成员hour的地址赋值给p1,使p1指向t1.hour
cout << *p << endl; //输出t1.hour
类型名 (*指针变量名)(参数列表);
如
void (*p)(); // p是指void型函数的指针变量
可以p指向一个函数,并通过指针变量调用函数
p = fun; //将fun函数的入口地址赋值给指针变量p,p就指向了函数fun
(*p)(); //调用fun函数
指向对象成员函数的指针变量 要匹配3方面(1)函数的参数类型和参数个数(2)函数返回的值的类型(3)所属的类
void (Time::*p2)();
数据类型名(类名::*指针变量)(参数列表);
也可以让它指向一个公用成员函数,一般形式为 指针变量 = &类名::成员函数名;
下面例子中涉及以上3个知识点
#include
using namespace std;
class Time
{
public:
Time(int, int, int);
int hour;
int minute;
int sec;
void get_time(); //公有成员函数
};
Time::Time(int h, int m, int s)
{
hour = h;
minute = m;
sec = s;
}
void Time::get_time()
{
cout << hour << ": " << minute << ": " << sec << endl;
}
int main ()
{
Time t1(6,0,0);
int *p1 = &t1.hour; //定义指向整型数据的指针变量p1指向t1.hour;
cout << *p1 << endl; //输出t1.hour
t1.get_time();
Time *p2 = &t1; //定义指向Time类对象的指针p2,并使p2指向t1;
p2->get_time(); //调用p2所指向对象(即t1)的get_time函数
void(Time::*p3)(); //定义指向Time 类公用成员函数的指针变量p3;
p3 = &Time::get_time; //使p3指向Time类公用成员函数get_time;
(t1.*p3)(); //调用对象t1中p3所指向的成员函数
return 0;
}
从上面看出 成员函数的入口地址为 类名::成员函数名
void(Time::*p3)(); //定义指向Time 类公用成员函数的指针变量p3;
p3 = &Time::get_time; //使p3指向Time类公用成员函数get_time;
//上述两句可以合为
void(Time::*p3)() = &Time::get_time;
一.3,指向当前对象的 this 指针
在第二章中我们提到:每个对象中的数据成员都分别占有储存空间,如果对同一个类定义n个对象,则就有n个相同大小的空间,存放n个对象的数据成员,但是,不用的对象都调用同一个函数的目标代码。
#include
using namespace std;
class Box
{
public:
Box(int h = 10, int w = 10, int len = 10);
int volume();
private:
int height;
int width;
int length;
};
Box::Box(int h, int w, int len)
{
height = h;
width = w;
length = len;
}
int Box::volume()
{
return (height * width * length);
}
int main ()
{
Box a, b, c;
}
那么当不同对象的成员函数引用数据时,怎么才能保证引用的是所指定对象的成员呢?假如对Box类 定义了 三个对象,a,b,c。如果有a.volume(),应该是引用对象中的a中的 height,width,length,计算出长方体a的体积。如果有b.volume()应该引用b中的 height,width,length,计算出长方体b的体积,而现在都用同一个函数代码,系统应该怎么使用它,分别引用a或b中的数据成员呢?
在每一个成员函数中都包含一个特殊的指针,这个指针的名字是固定的,称为this。它是指向本类对象的指针,他的值是当前被调用的成员函数所在的对象的起始地址。
例如当调用成员a.volume时,编译系统就把对象a的起始地址符给this指针,于是在成员函数引用数据成员时,就按照this的指向找到对象a的数据成员。例如volume函数要计算height * width * length的值 实际执行的是
this->height * this->width * this->length
由于this是指向a的又相当于
a.height * a.width * a.length
int Box::volume()
{
return (height * width * length);
}
c++ 执行实际是
int Box::volume(Box *this)
{
return (this->height * this->width * this->length);
}
即在成员函数的形参列表中增加一个this指针,在调用该成员函数是,实际上是用以下调用方式
a.volume(&a);
将对象a的地址传给形参this指针。然后按this的指向去引用其他成员。(这些都是编译系统自己实现的)
3个都是等价的
return (this->height * this->width * this->length);
return (height * width * length);
return ((*this).height * (*this).width * (*this).length);
一.4,公用数据的保护
例如
Time const t1(12, 34, 56); //定义t1是常对象
常对象的意思是,在t1生命周期中,t1中的所有数据成员的值都不被修改。所有你只要有希望保护的值(或者人啊 '_')都可以声明为常对象。
常对象定义的一般形式
类名 const 对象名 [ ( 实参表 ) ];
或者
const 类名 对象名 [ ( 实参表 ) ];
如果一个对象被声明为常对象,那么只能调用它的常成员函数,而不能调用该对象的普通成员函数。常成员函数是常对象对外的唯一接口。
const Time t1(10, 9, 8); //定义对象t1为常对象
t1.get_time(); //企图调用对象t1中的普通成员函数,非法
这是为了防止普通成员函数会修改常对象中数据成员的值。就算在get_time函数内并没有修改常对象中的数据成员,也不行。因为编译系统会充分考虑到出现的情况,意思就是对不安全的因素以排斥;
有人会问:为什么编译系统不会专门检查函数的代码呢?看它是否修改了常对象中的数据成员的值内?实际上函数的定义与声明可能不在一个源程序文件中,而编译器真实以一个源文件为单位的,无法侧出两个源程序文件之间是否有矛盾,如果有错,只有在链接在运行阶段才能发现。这给试调带来不便。
简单来书说就是:编译系统只检查函数的声明,只要发现调用了常对象的成员函数,而且该函数未被声明为const,就会报错
void get_time() const; //将函数声明为const
常成员函数可以访问常对象中的数据成员,但不允许修改常对象中数据成员的值。
但是如果有编程要求,常对象中的某个数据成员的值也是可以改的,对数据声明为mutable
mutable int count;
把count声明为可变数据成员,这样就可以声明为const的成员函数来修改它的值。
(1)常数据成员
还是 const来声明,注意:只能通过构造函数的参数初始化表对常数据成员进行初始化,任何其他函数都不能对常数据成员赋值
const int hour; //定义hour为常数据成员
Time::Time (int h) //非法,不能对之赋值
{
hour = h;
}
Time::Time(int h):hour(h){} //通过参数初始化表对常数据成员hour进行初始化。
(2)常成员函数
一般成员函数可以引用本类中的非const数据成员,也可以修改他们,如果将成员函数声明为常成员函数,则只能引用本类的数据成员而不能修改。
例如只用于输出数据
void get_time() const;
类型名 函数名(参数表)const;
const是函数类型的一部分,声名和定义函数时都需要有const关键字,在调用时不需要。
常函数成员可以引用非const的数据成员,const数据成员可以被const成员函数引用,也可以被非const成员函数引用
数据成员 | 非const得普通成员函数 | const成员函数 |
非const的普通数据成员 | 可以引用也可以改变值 | 可以引用,但不可以改变值 |
const数据成员 | 可以引用,但不能改变值 | 可以引用,但不可以改变值 |
const对象 | 不允许 | 可以引用,但不可以改变值 |
如果已经定义了一个常对象,只能调用其中的const成员函数,而不能调用非成员函数。这是为了保护数据的安全,如果需要访问常对象中的数据成员,可以将常对象中所有成员函数都声明为const成员函数,并确保在函数中不修改对象中的数据成员。
常成员函数不能调用另一个非const成员函数。
Time t1(10, 12, 15), t2; //定义对象
Time * const ptr1; //const位置在指针变量名前,指定ptr1是常指针变量
ptr1 = &t1; //ptr1指向对象t1,此后不再改变指向
ptr1 = &t2; //错误,ptr1不能改变指向
一般形式
类名 * const 指针变量名
一般形式,
const 类型名 *指针变量名;
如果一个人变量已被声名为常变量,只能用指向常变量的指针变量指向它,而不能用一般指针。
const char c[] = "boy"; //定义const 型的char数组
const char *p1; //定义p1指向const型的char变量的指针变量
p1 = c; //合法p1指向常变量 (char数组的首元素)
char *p2 = c; //不合法,p2不是指向常变量的指针变量
char c1 = 'a'; //定义字符变量c1,它并未声名为const
const char *p; //定义了一个指向变量的指针p;
p = &c1; //使p指向字符变量c1;
*p = 'b'; //非法 , 不能通过p改变c1的值;
c1 = 'b'; //合法,没有通过p访问c1,c1不是常变量
上面这个例子。并不意味着吧c1也声名为常变量,而是在用指针变量访问c1期间,c1具有常变量特征,其值不能改变。但是在其他情况下 还是c1还是个变量,其值可以改变。
Time t1(10, 12, 15); //定义Time类对象t1,它是非const型对象
const Time *p = &t1; //定义p是之指向常对象的指针变量,并指向t1
t1.hour = 18; //合法t1不是常变量
(*p).hour = 18; //非法,不能通过改变指针变量的改变t1的值
Time *const p; //指向对象的常指针变量
const Time *p; //指向常对象的指针变量
(5)对象的常引用
void fun(Time &t){
t.hour = 10;
}
如果不希望在函数中修改实参t1的值可以吧fun函数的形参t声明为const
void fun(const Time &t)
Const 小结
形式 | 含义 |
Time const t1; | t1是常对象,其值在任何情况下下都不能改变 |
void Time : : fun() const; | 是Time类中的常成员函数,可以引用,但是不能修改本类中的数据成员 |
Time * const p; | p是指向Time类对象的常指针变量,p的值(p的指向)不能改变 |
const Time * p; | p是指向Time类常对象的指针变量,p指向类对象的值不能通过p来改变 |
const Time &t1 = t; | t1是Time类对象 t 的引用,二者指向同一存储空间,t的值不能改变 |