1.内联函数 inline
(1)含义:
C++内联函数是通常与类一起使用。如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字inline,在调用函数之前需要对函数进行定义。
(2)内联函数定义和声明:
显式声明:在函数名前面放置关键字inline
隐式声明:将函数体直接放在类中的,即使没有使用inline说明符函数。
(3)注意:如果已定义的函数结构复杂,编译器会忽略inline限定符(使用内联函数只是对编译器的建议,编译器自己也会考虑函数的结构复杂性)。
(4)例子:
显式声明:
inline int entermax( int x , inty)
{
return (x>y) ? x:y; //判断IF(x>y),ture返回x,false返回y.
}
int mian()
{
cout<< entermax(2,1);//函数执行时将内联函数的代码直接嵌入到主调函数,省去保存现场、传递参数等流程,提高执行效率。
}
隐式声明:
class MyClass
{
public:
MyClass();
int max(int a,intb)将函数体直接放在类中的,没有使用inline说明符函数
{
return (a>b)?a:b;
}
}
2.类成员的访问控制;private,protected,public
(1)私有成员:关键字private(在类中没有指出的成员默认是private属性)
只能被该类中的成员函数存取private成员数据;
(2)公有成员:关键字public
可以被该类中的成员函数存取public成员数据;
也可以被该类之外的函数存取public成员数据;
(3)保护成员;关键字protected
可以被该类中的成员函数存取protected成员数据;
也可以被该类的派生类的成员函数存取public成员数据;
3.构造函数
(1)含义:
构造函数是一个和类同名的函数,没有返回类型。被定义为public函数,在定义对象时由系统调用,其他任何时候任何函数都无法再次调用构造函数。
(2)声明的定义:
隐式声明:在说明类时没有声明/定义,系统会生成一个默认构造函数(即使该构造函数什么也不做,在类中也不显示)
显式声明:与类同名,手动定义恰当的构造函数,可以在创建类的对象时获得一个初始值。
(3)注意:
构造函数可以访问类的所有数据成员;
可以是内联函数,可以带参数表,可以带默认值,可以重载。
(4)例子;
class MyClass
{
int a , b;
public:
MyClass(int x,int y) //此处为隐式内联构造函数
{ a=x;
b=y; }
}
void MyClass::MyClass(int x=0)//带默认参数的构造函数,相对于MyClass(int x,int y)也是一个重载函数
{
a=x;定义类对象时,给出实参,不给出默认0来初始化数据成员int a;
}
3.1复制构造函数
(1)含义:
特殊的构造函数,作用在于用一个已经存在的对象,来初始化另一个新的对象。
复制构造函数声明:类名(类名 &引用对象名)
(2)例子:
class MyClass
{
int a,b;
public:
MyClass(int x,int y)//构造函数
{ a=x;
b=y; }
MyClass(MyClass &m1)//复制构造函数,此处的m1理解为一个对象参数
{ a=m1.a ;
b=m1.b; }
}
int main()
{
MyClass mm1(1,2);//定义对象mm1系统调用了构造函数MyClass(int x,int y)
MyClass mm2 (mm1);//定义对象mm2, 系统调用了复制构造函数
}
################
注意:复制构造函数的数据成员必须写在“=”前面,如“a=m1.a”,而不能“m1.a=a”;否则后者并不能起到复制的作用。
#########################################################
4.析构函数
(1)含义:
与构造函数相反,完成对象被删除前的收尾工作,在程序执行过程中,某个对象的生存周期结束时,系统自动调用析构函数。
(2)析构函数的声明和定义:
class MyClass
{
int a , b;
public:
MyClass(int x,int y); //构造函数
{ a=x;
b=y; }
~ MyClas() ; //析构函数
}
(3)注意:
析构函数不接受参数,只能有一个(也不能重载、复制)
可以是虚函数;
5.对象数组和对象指针
类作为一种C++的构造数据类型,可以像其他基本类型一样定义数组,指针等。
5.1对象数组
(1)含义:
对象数组中的每一个元素都是同一类的对象。
(2)例子:
class MyClass
{
int a , b;
public:
MyClass(); //构造函数
MyClass(int x,int y) //一个重载的构造函数
{ a=x;
b=y; }
~ MyClas() ; //析构函数
}
int main(
{ MyClass m[3]={ MyClass(),MyClass(),MyClass(1,2)};//对象数组中的每一个元素可以用不同的构造函数初始化。
}
5.2对象指针
(1)含义,用于存放对象地址的变量,遵循一般指针的规则。
(2)用法:
(*对象指针名). 成员名 or 对象指针名->成员名
(3)例子:
class MyClass
{
int a , b;
public:
MyClass(); //构造函数
MyClass(int x,int y) //一个重载的构造函数
{ a=x;
b=y; }
~ MyClas() ; //析构函数
}
int main(
{ MyClass m1(1,2);
MyClass *m2;//声明MyClass类的对象指针变量m2;
m2=&m1;//将对象m1的地址赋值给m2,使m2指向m1;
}
5.3 this指针
一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。
作用:
编译器自动将参数传递给函数,使得不同对象调用同一个函数代码段
6.静态成员
为了实现类的多个对象之间的数据共享。静态成员不属于某个对象,它是为某个类的所有对象所共有的,静态成员属于某个类。
6.1静态数据成员
(1)含义:
类中关键字static修饰的数据成员称为静态数据成员。对于类的普通数据成员,类的每个对象都拥有备份(针对类的普通数据成员,每个对象都有一块各自的存储空间来存储它们),这是每个对象相互区分开的保证。
但是类的某个数据成员被声明为static的,那么该类的所有对象共享该静态数据成员的存储空间,其中在声明一个类的对象时,只为该对象分配普通数据成员所需存储空间,并不分配静态数据成员所需的存储空间。
(2)声明和定义,例子如:
class Point
{
private:
static int count;
// static 类型名 数据成员名;说明这是类的所有对象共享的成员,不属于任何一个对象私
有,因此,在声明类的对象时均不存储该数据。
public:
Point()
{ count++ }
void PointSum()
{ cout<<count }
}
int Point::count=0;//类型名 类名::数据成员名=初值;在静态存储区分配空间,只能在类外定义一次。不设初值时,默认为0使用.
int main()
{ Point p1;//定义对象p1,调用构造函数,使得count+1
Point p2;//定义对象p2,调用构造函数,使得count+1
p1.PointSum();//结果显示:2
p2.PointSum();//结果显示:2
}
class Point
{
private:
static int count;
// static 类型名 数据成员名;说明这是类的所有对象共享的成员,不属于任何一个对象私
有,因此,在声明类的对象时均不存储该数据。
public:
Point()
{ count++ }
void PointSum()
{ cout<<count }
}
int Point::count=0;//类型名 类名::数据成员名=初值;在静态存储区分配空间,只能在类外定义一次。不设初值时,默认为0使用.
int main()
{ Point p1;//定义对象p1,调用构造函数,使得count+1
Point p2;//定义对象p2,调用构造函数,使得count+1
p1.PointSum();//结果显示:2
p2.PointSum();//结果显示:2
}
(3)注意:
静态数据成员是在静态存储区分配空间,具有静态生命期,即存在于程序运行期间,直到程序运行结束,与对象的生、死无关。
6.2静态成员函数
(1)与静态数据成员类似,属于整个类。函数体实现在类体或者类外都可以。
(2)在静态成员函数中,可以直接引用静态数据成员,但不能直接引用非静态成员(包括数据成员、其他成员函数)。
(3)在静态成员函数中引用非静态成员,可先通过参数传递的到对象名,再通过对象名访问非静态成员。
(4)静态成员函数调用方式:
类名::静态成员函数名(参数)
或 对象名.静态成员函数名(参数)
6.1的例子改变如下;
class Point
{
private:
static int count;
public:
Point()
{ count++ }
static void PointSum()
{ cout<<count }
}
int Point::count=0;
int main()
{ Point p1;//定义对象p1,调用构造函数,使得count+1
Point p2;//定义对象p2,调用构造函数,使得count+1
p1.PointSum();//结果显示:2
p2.PointSum();//结果显示:2
Point::PointSum();//结果显示:2,可见采用静态成员函数的优点是不依赖任何对象,可以直接访问静态数据成员。
}
7.友元
静态成员实现了同类对象间的数据共享,友元则是为了不同类(或对象)的成员函数之间、类的成员函数与一般函数之间进行数据共享。
友元对类的封装和隐蔽性有影响,一般情况下建议谨慎使用友元。用关键字friend修饰,可以是友元函数、友元类。
7.1友元函数
(1)含义:
有关键字friend修饰,在友元函数的函数体中可以通过对象名来访问本类所有成员。
(2)例子:
class Point
{
int x,y;
public:
Point(int a=0,int b=0)
{
x=a;
y=b;
}
int getx()
{
return x;
}
friend int dist(Point &p1)//友元函数声明
{
return p1.x;//此处通过对象访问本类成员
}
};
int main()
{
Point p(10,15);
cout<<dist(p);
return 0;
}
(3)注意:
在一个类的任何成员函数可以说明为其他类的友元函数,访问通过相应的类和对象。
7.2友元类
(1)含义:
若说明A类是B类的友元类,那么A可以访问B类所有成员。
(2)例子:
class Point
{
int Px=0;
public:
int getX()
{return Px;
}
friend class B;//声明B类是我的友元类,那么B可以直接访问Point的成员。
};
class B
{
Point p1;
public:
int getPointX()
{ return p1.Px;//B可以直接访问Point类的private成员Px;
}
};
注意:若不使用友元,B的成员要访问Point类的private成员Px,可以通过Point的public成员间接访问private成员Px。以上红色代码改为:return p1.getX()即可.
(3)注意:
友元类提供了直接访问的方式,但是类的封装受到了破坏。在常规访问、友元访问两者之间要做好取舍。
1.友元关系不能传递
2.友元关系是单向的
3.友元关系不能被继承
8. const常类型
在C++中,静态、友元、以及常规类间访问等数据交流共享一定程度会使得数据有不想要的被修改,想要某个成员不被修改,可以使用const修饰
8.1常对象
(1)含义:
定义对象时声明为常对象,那么该对象所具有的的数据成员在该对象的生存周期之内都不能被修改。类似于常变量const 数据类型 标识符=初始值(C++中类是合法的数据类型,理论上原理相同,只不过对象包含的所有数据成员都不能被修改)
注意:#define定义的符号常量,只是用一个符号代替指定的那个字符串(如#define PI 3.14),预编译时只是把所有PI替换为3.14罢了,它没有类型,也没有分配内存;而const修饰的常对象(变量)具有类型、也要分配内存,只是该常变量(对象)的值不允许被改变,因此常变量(对象)在声明时必须初始化。
(2)例子:
const 类名 对象名(初始值);
类名 const 对象名(初始值);//const和类名谁在前在后都行
(常变量:const int a=15;//a的生存周期内a永远是15,值不能被修改,若有则代码报错)
(3)注意注意注意:
常对象只能调用常成员函数。
8.2 const修饰的类成员
const可以修饰类中的成员(数据成员、成员函数),分别称为常数据成员、常成员函数。
8.2.1常数据成员
(1)含义:
和一般数据一样,类的数据成员可以说明为常变量,但是区别是:类中的常变量数据成员不能被在声明时初始化(因为类的成员不能被初始化),只能在构造函数初始化列表被初始化。
(2)声明方式;
class A
{ const int x; //类成员不能被初始化,即使它是常变量
public:
A(int y):x(i)
{} //常数据成员只能通过构造函数初始化列表被初始化
//若构造函数写成A(int y){ x=I }会报错
}
(3)例子:
class A
{
const int x;
public:
A(int y):x(y)
{}
int shuchuAx()
{
return x;
}
};
int main()
{
A a1(15);
cout<<a1.shuchuAx();
return 0;
}
8.2.2常成员函数
(1)含义:用const修饰的成员函数称为常成员函数。格式:类型 成员函数名(参数) const
(2)注意:
1.const 是函数的一部分,在函数的定义部分也要带const.
2.常对象只能调用常成员函数;
3. 对象能调动成员函数,包括常成员函数,但是在调用期间,该对象被认为是常对象,因此:常成员函数不能更新目的对象的数据成员
4.const可以用于重载函数的区分。但如果只有const关键字作为重载函数的区分(即参数表相同或都没有参数),那么非const对象调用函数时都能匹配,但是此时编译器会自动选择最相近的函数——即不带const修饰的那个函数。
(3)例子:
class A
{
const int x;
public:
A(int y):x(y)
{}
void shuchuAx() const //用const关键字区分的重载函数
{
cout<<x;
cout<<"const has been used IS ture";
}
void shuchuAx()
{
cout<<x;
cout<<"const has been used IS false";
}
};
int main()
{
A a(10);//非const对象
a.shuchuAx();//调用了shuchuAx()函数
A const a1(20);// const对象
a1.shuchuAx();//调用了shuchuAx() const函数
return 0;}
结果: