请看下面的类及其调用:
#include <iostream>
using namespace std;
class CBox
{
private:
float m_long,m_width,m_height;
void mytest()
{
cout<<endl
<<m_long
<<endl;
}
public:
void testcall();
CBox(float lv,float wv=0,float hv=0):m_long(lv),m_width(wv),m_height(hv)
{
printf("Construct created!\n");
}
CBox();
friend void readmytest(CBox box);
};
void main()
{
CBox mybox(3,2,1);
mybox.testcall();
CBox testbox;
testbox.testcall();
readmytest(mybox);
}
CBox::CBox()
{
printf("No Paramters construct created!\n");
}
void readmytest(CBox box)
{
printf("the Volumn:%6.2f\n",box.m_height*box.m_long*box.m_width);
}
void CBox::testcall()
{
printf(" 长:%6.2f\n 宽:%6.2f\n 高: %6.2f\n 体积为:%6.2f\n",m_long,m_width,m_height,m_long*m_width*m_height);
mytest();
}
1.声明类时用关键字class,类名为CBox;
private和public是类成员可见性限制符,如:private只能被类内的成员来调用 ,public能被所有引用此类的对象来调用。
还有一个是protected,是可以被其子类来访问。
2.类中所有的函数或数据字段都为类的成员,函数也叫函数成员或方法成员,数据叫字段也叫数据成员。
m_long
m_width
m_height
以上三个为数据成员,在C中以m(member)开头。
mytest()
testcall()
CBox()
等为函数成员
其中CBox()函数,你会发现它的前面没有返回值且和类名一样,此函数叫构造函数。
构造函数的作用为产生此类的对像,并对内部的数据等进行初如化。
一个类可以有多个构造函数。
3.构造函数
如果在一个类的声明中没有声明一个构造函数,则编译器会用一个不带任何参数的并不做任何事的构造函数来产生一个对像。一旦你写了一个构造函数,则在产生对像前,编译器便认为你不再用它提供的构造函数了,所以如果你声明的构造函数不存在,就会报错。
如在本例中,有二个CBox构造函数,一个是带参数的,一个是不参数的。如果此类根本没有构造函数,如
CBox testbox;此时编译器会认为你调用它给你提供的构造函数来处理,这样就会正常编译,但一旦你声明了上面带参数
的构造函数而没有声明不带参数的构造函数,你还用CBox testbox;编译器就会报错,提示没有这样的函数供你调用。国为
一旦你声明了构造函数,则以后产生对象时就会找你类中你声明的函数,它认为你不在依靠它了。
CBox(float lv,float wv=0,float hv=0):m_long(lv),m_width(wv),m_height(hv)
{
printf("Construct created!\n");
}
CBox();
以上两个都为构造函数,上面的为参函数,下面为不带参数。
构造函数中wv 和hv都有默认值0,即在调用此函数时,如果你没有给出实参,则编译器会用它的默认参数来填充。
如 CBox mybox(3),此时编译器会让lv=3, wv=hv=0.
m_long(lv),m_width(wv),m_height(hv)是什么意思呢?
我们知道给一变量赋值时可以这样做: int leftvalue=20 或int leftvalue(20). 这里用的是后一种做法,即给 m_long等成员变量赋值。
在类构造函数声明时后加冒号并给成员变量赋值,我们称之为初始化列表。
相当于这样的构造函数:
CBox(float lv,float wv=0,float hv=0)
{
printf("Construct created!\n");
m_long=lv;
m_width=wv;
m_height=hv;
}
我们再看两处构造函数,如果也把lv设置默认值,此时再运行main()函数,编译器会报错,为什么?
因为如果里面全有默认值,则编译器不知道你调用哪个构造函数,所以会报错。这个就是我们提到的函数重载的问题了。
注:如果用到初始化列表,则构造函数的定义即函数体也要在本类中,否则不能编译。
4.类中函数的声明和定义
如果函数体也在类内定义,则像普通函数一样编写即可,如 void mytest()函数。声明和定义在一起的类成员函数也叫内联函数。
内联函数的格式为:
inline double getValue(double v1)
{
return v1;
}
内联函数头前应加上inline关键字。 一般内联函数都是比较短小精悍的那种,便于用时把代码插到调用的地方,不用时则不调用,效率比较高。
但像回调函数、递归调用等则不适合。
如果只在类内声明,函数定义在类外面,就一定要在定义的名称前加上类名及类作用域符号(::),如:
testcall()和CBox()函数
void CBox::testcall()
{
printf(" 长:%6.2f\n 宽:%6.2f\n 高: %6.2f\n 体积为:%6.2f\n",m_long,m_width,m_height,m_long*m_width*m_height);
mytest();
}
CBox::CBox() //构造函数没有返回值
{
printf("No Paramters construct created!\n");
}
5.友元函数
友元函数不属于类成员,但可以访问对像中的所有成员,它只是一个全局普通的函数。
友元函数的关键字为friend.
friend void readmytest(CBox box);
友元函数的定义可以在类内也可以在类外,在类外时和普通的定义一样。
void readmytest(CBox box)
{
printf("the Volumn:%6.2f\n",box.m_height*box.m_long*box.m_width);
}
这个readmytest函数是普通全局的,在任何地方都可以调用,不受CBox类的限制,因为它不属于此类。但它可以访问box对像的数据成员。
6. this指针
类产生每一个对像时,都会在内存中有个不同指针指向这此对像,即this这个指针。一般在类中编译器会自动调用此指针,不用显式写出。
如果赋值变量和类的数据成员一样时,为了便于人员解读,可以用this->m_long=m_long的样式来处理,这样我们便知道前面的m_long是
类成员,后面m_long为要赋值的变量。因为this为指针类型,则符号为->.