1. 类访问修饰符
public > protected > private
1. public————在类的外部可以被访问
2. protected————只能在类的内部、友元函数、派生类(子类)中访问
3. private————只能在类的内部、友元函数中访问
若不声明访问类型,则默认是 private类型
一般在private中定义成员变量,在public中定义相关get、set函数,以便在类的外部设置和使用数据
一般在protected中定义派生类要使用的成员变量。
继承时的特点
- public 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中变成:public, protected, private
- protected 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中变成:protected, protected, private
- private 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中变成:private, private, private
如果继承时不显示声明是 private,protected,public 继承,则默认是 private 继承,在 struct 中默认 public 继承
但无论哪种继承方式,上面两点都没有改变:
1.private 成员只能被本类成员(类内)和友元访问,不能被派生类访问;
2.protected 成员可以被派生类访问。
2. 构造/析构函数
构造函数——用于设置类中成员变量的初始值
- 构造函数名与类名相同,不会返回任何类型,包括void
- 若不设置构造函数,则系统会自动设置一个无参的构造函数;若设置的有构造函数,则系统不会自动设置
- 在每次创建对象时执行,用于给对象赋初始值
使用初始化列表来初始化字段
有参的构造函数可以写成初始化序列的形式
class Point{
public:
int x, y ;
Point(int a, int b):x(a),y(b){}
}
拷贝构造函数——使用同一类中之前创建的对象来初始化新创建的对象
- 是一种特殊的构造函数,当使用另一个同类型的对象来初始化新对象或对象作为函数的形参或返回值时使用
- 如果在类中没有定义拷贝构造函数,编译器会自行定义一个
- 如果类带有指针变量,并有动态内存分配,则必须定义一个拷贝构造函数
析构函数——在结束程序时释放资源
- 函数名与类名相同,不过在类名前加了~,不返回任何类型,包括void
- 在每次删除所创建的对象时执行,用于在跳出程序前释放资源
3. 类的友元函数——friend
一个类中如果声明了友元函数,则友元函数可以使用这个类所有的private和protected成员
- 类中要用friend声明友元函数,友元函数的定义写在类外
- 友元可以是一个函数,也可以是一个类,友元类的所有成员都是友元
- 友元函数与类的成员函数不同,友元函数没有this指针,且可以直接调用,不需要通过对象调用
#include<iostream>
using namespace std ;
class Box
{
double width; //默认为private
public:
friend void printWidth(Box box); //有友元函数
friend class BigBox; //友元类
void setWidth(double wid); //成员函数
};
class BigBox //友元类
{
public :
void Print(int width, Box &box)
{
box.setWidth(width); //BigBox是Box的友元,可以直接使用Box的成员
}
};
void Box::setWidth(double wid) // 成员函数定义
{
width = wid;
}
void printWidth(Box box) // 友元函数
{
cout << "Width of box : " << box.width << endl;
}
int main() // 程序的主函数
{
Box box;
BigBox bigbox;
box.setWidth(10.0); // 使用成员函数设置宽度
printWidth(box); // 使用友元函数输出宽度
big.Print(20, box); // 使用友元类中的方法设置宽度
return 0;
}
4. inline 内联函数
即代码替换。直接将函数体替换到函数调用处。
程序的局部数据放置在栈空间中,当频繁调用小函数时就会占用大量的栈空间。同时频繁调用函数也会拖慢程序运行速度。因此,一般将频繁使用的小函数设为inline。
如下述例子,printf中的inline_test(i)在编译时被替换为(num % 2 > 0) ? "奇" : "偶" 。
#include <stdio.h>
#include<string.h>
// 函数定义为inline即:内联函数
inline char* inline_test(int num)
{
return (num % 2 > 0) ? "奇" : "偶";
}
int main()
{
int i = 0;
for (i = 1; i < 10; i++)
{
printf("inline_test: i:%d 奇偶性:%s\n", i, inline_test(i));
}
return 0;
}
- inline 的使用是有所限制的,inline 只适合函数体内代码简单的涵数使用,不能包含复杂的结构控制语句例如 while、switch,并且不能内联函数本身不能是直接递归函数(即,自己内部还调用自己的函数)。
- inline 函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思,它如果认为函数不复杂,能在调用点展开,就会真正内联,并不是说声明了内联就会内联,声明内联只是一个建议而已。
- 建议 inline 函数的定义放在头文件中,将内联函数的定义放在头文件里实现是合适的,省却为每个文件实现一次的麻烦。
类内的成员函数
对于类中的成员函数,若在类中就给出函数定义,则默认是内联的,若将函数定义写在类外,则需要写上inline才是内联
另:复杂函数不要内联,且内联是以代码膨胀为代价的,慎用inline
5. this指针
- this可以理解为对象的指针。
- this指针是所有成员函数的隐含参数,在成员函数内部,this可以用来指向调用对象
- 在成员函数内部,使用方法:this->成员变量,this->成员函数
class Box
{
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
public:
Box(double l=2.0, double b=2.0, double h=2.0) //构造函数
{
cout <<"Constructor called." << endl;
length = l;
breadth = b;
height = h;
}
double Volume() //成员函数
{
return length * breadth * height;
}
int compare(Box box) //成员函数
{
return this->Volume() > box.Volume(); //用this调用对象的volume函数
}
};
6. 类的静态成员
一个类的静态成员包括静态成员变量和静态成员函数。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。
静态成员变量
- 静态成员变量在所有对象中都是共享的
- 如果没有初始化语句,静态成员变量默认为0
- 静态成员变量在类中声明,在类外初始化
- 在其他函数中可直接调用,方法: 类名::静态成员变量名
- 可以利用静态成员变量了解创建了多少对象(构造函数使用了多少次)
静态成员函数
- 静态成员函数即使在类对象不存在的情况下也能被调用
- 静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。
- 静态成员函数有一个类范围,他们不能访问对象的 this 指针
- 其他函数中可直接调用,方法: 类名::静态成员函数名()
#include <iostream>
using namespace std;
class Box
{
public:
static int objectCount; //静态成员变量,记录创建了多少个对象
Box(double l=2.0, double b=2.0, double h=2.0) // 构造函数定义
{
length = l;
breadth = b;
height = h;
objectCount++; // 每次创建对象时增加 1
}
double Volume()
{
return length * breadth * height;
}
static int getCount() //静态成员函数
{
return objectCount;
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
// 初始化类 Box 的静态成员
int Box::objectCount = 0;
int main(void)
{
// 在创建对象之前输出对象的总数
cout << "Inital Stage Count: " << Box::getCount() << endl;
Box Box1(3.3, 1.2, 1.5); // 声明 box1
Box Box2(8.5, 6.0, 2.0); // 声明 box2
// 在创建对象之后输出对象的总数
cout << "Final Stage Count: " << Box::getCount() << endl;
return 0;
}