类和对象的区别
类是抽象的,对象是具体的,所以,类不占用内存,而对象占用内存。总之一句话,类是对象的抽象,对象是类的具体事例。
例如:类是水果的话,那么对象就是苹果……
类中的函数
1、类的成员函数:是指把函数的原型和定义写在类的内部的函数。是类的成员,可以操作类中的所有对象,可以访问对象中的所有成员。
类的成员函数可以定义在类的内部,也可以放在类的外部使用(::)域操作符来定义成员函数,看例子:
class Box:
{
public:
int length;
int width;
int heigth;
int GetVolume(void)//内部定义成员函数
{
return length*width*heigth;
}
};
int Box::GetVolume(void)//外部定义成员函数
{
return length*width*heigth;
}
调用成员函数是在对象是使用点运算符(.),这样就可以操作与该对象相关的数据。
2、类的访问修饰符:public、private和protected。默认状态下是private类型的。
公有成员是可以在类外部访问的,您可以不使用任何成员函数来设置和获取公有变量的值。就是说你可以直接用对象+“.”(点运算符)的方式来为公有变量赋值。
私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。(这个和Java不一样,Java类中默认是public)
默认情况下,类的所有成员都是私有的。
实际操作中,我们一般会在私有区域定义数据,在公有区域定义相关的函数,以便在类的外部也可以调用这些函数。这个方式确实好,有点里应外合的感觉。
保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。
例如:
#include <iostream>
using namespace std;
class Box
{
protected:
double width;
};
class SmallBox:Box // SmallBox 是派生类
{
public:
void setSmallWidth( double wid );
double getSmallWidth( void );
};
// 子类的成员函数
double SmallBox::getSmallWidth(void)
{
return width ;
}
void SmallBox::setSmallWidth( double wid )
{
width = wid;
}
// 程序的主函数
int main( )
{
SmallBox box;
// 使用成员函数设置宽度
box.setSmallWidth(5.0);
cout << "Width of box : "<< box.getSmallWidth() << endl;
return 0;
}
3、构造函数和析构函数:这是两个相反的函数,构造函数是在创建对象时调用,而析构函数是在销毁对象时调用。
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。
默认的构造函数没有任何参数,但如果需要,构造函数也可以带有参数。这样在创建对象时就会给对象赋初始值。
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
#include <iostream>
using namespace std;
class Line
{
public:
void setLength( double len );
double getLength( void );
Line(); // 这是构造函数声明
~Line(); // 这是析构函数声明
private:
double length;
};
// 成员函数定义,包括构造函数
Line::Line(void)
{
cout << "Object is being created" << endl;
}
Line::~Line(void)
{
cout << "Object is being deleted" << endl;
}
void Line::setLength( double len )
{
length = len;
}
double Line::getLength( void )
{
return length;
}
// 程序的主函数
int main( )
{
Line line;
// 设置长度
line.setLength(6.0);
cout << "Length of line : " << line.getLength() <<endl;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Object is being created
Length of line : 6
Object is being deleted
可见构造函数与析构函数表面上是一个“~”的差别,其实作用恰恰相反,一个生成,一个回收。
4、拷贝构造函数:是一种特使的构造函数,在创建对象时,用同一类中之前创建的对象来初始化新创建的对象。
拷贝构造函数调用的三种形式
1.一个对象作为函数参数,以值传递的方式传入函数体;
2.一个对象作为函数返回值,以值传递的方式从函数返回;
3.一个对象用于给另外一个对象进行初始化(常称为复制初始化)。
总结:当某对象是按值传递时(无论是作为函数参数,还是作为函数返回值),编译器都会先建立一个此对象的临时拷贝,而在建立该临时拷贝时就会调用类的拷贝构造函数。
如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。该构造函数完成对象之间的位拷贝。(位拷贝又称浅拷贝,后面将进行说明。)自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,提高源码效率。拷贝构造函数的最常见形式如下:
classname (const classname &obj) {
// 构造函数的主体
}
在这里,obj 是一个对象引用,该对象是用于初始化另一个对象的。
在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。事实上这就要用到深拷贝了,要自定义拷贝构造函数。(这一段其实很好理解)
深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝,浅拷贝资源后在释放资源的时候会产生资源归属不清的情况导致程序运行出错。一定要注意类中是否存在指针成员
5、友元函数:它不是成员函数,但是可以访问类的所有成员,包括private和protected修饰的成员。为什么它不是成员函数呢?还是因为它不受访问修饰符的限制。
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend,例如:
class Box
{
double width;
public:
double length;
friend void printWidth( Box box );
void setWidth( double wid );
};
6、this指针
当你进入一个房子后,
你可以看见桌子、椅子、地板等,
但是房子你是看不到全貌了。
对于一个类的实例来说,
你可以看到它的成员函数、成员变量,
但是实例本身呢?
this是一个指针,它时时刻刻指向你这个实例本身
1.作用:
一个对象的this指针并不是对象的一部分,所以并不会影响对象的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。
2.使用:
一种情况就是,在类的非静态成员函数中返回类对象本身的时候,直接使用 return *this;
另外一种情况是当参数与成员变量名相同时使用this指针,如this->n = n (不能写成n = n)。
//来自百度百科
#include<iostream>
using namespace std;
class Point
{
private:
int x,y;
public:
Point(int a,int b)//构造函数
{
x=a;
y=b;
}
void MovePoint(int a,int b)
{
x+=a;
y+=b;
}
void print()//打印函数
{
cout<<"x="<<x<<"y="<<y<<endl;
}
};
int main()
{
Point point1(10,10);//创建一个point1的对象
point1.MovePoint(2,2);//调用MovePoint()函数
point1.print();
return 0;
}
MovePoint函数的原型应该是 void MovePoint( Point *this, int a, int b);第一个参数是指向该类对象的一个指针,我们在定义成员函数时没看见是因为这个参数在类中是隐含的。这样point1的地址传递给了this,所以在MovePoint函数中便显式的写成:
void MovePoint(int a, int b) { this->x +=a; this-> y+= b;}