目录
类的定义
class用来定义类,类有三个访问权限,private、public和protected
class 类名
{
private:
//成员属性or成员函数(成员方法)
public:
//成员属性or成员函数(成员方法)
protected:
//成员属性or成员函数(成员方法)
};
- class是定义类的关键字,class后面跟类名,类名一般首字母大写
- 类中包括成员属性和成员函数,成员属性代表对象的属性,成员函数代表对象的行为
- private、public和protected关键字是访问限定符,用于设置类成员的访问权限,顺序可以随意设定,默认时为私有(private)
example:声明一个学生类
分析:学生类中需要有姓名、学号、性别等属性;对每个学生的基本操作有输入信息、输出信息等。学生类的声明如下。
class Student//声明类
{
private://访问权限:私有成员
string m_name;//属性,数据成员,表示姓名
string m_num; //属性,数据成员,表示年龄
string m_sex; //属性,数据成员,表示性别
public://访问权限:公有成员
Student(){}; //行为,成员函数原型声明,表示构造函数
void input(); //行为,成员函数
void output();
};//类声明结束
员工类
class Worker
{
private://访问权限为私有类型
int w_name;//属性,数据成员,员工姓名
int w_id;//属性,数据成员,员工编号
int w_age;//属性,数据成员,员工年龄
public://访问权限为公有类型
Worker();//构造函数
void input();//成员函数,输入信息
void output();//成员函数,输出信息
};
成员访问权限
可以定义三种不同的访问限定符,分别是public(公有类型)、private(私有类型)和protected(保护类型)。
public(公有类型)
public声明成员为公有成员。完全公开。都可以访问
class Human
{
public: //声明类的公有成员
int high; //身高
int weight; //体重
void GetHigh()
{
cout << "身高:" << high << endl;
}
void GetWeight()
{
cout << "体重:" << weight << endl;
}
};
int main()
{
Human zhangsan; //定义类的对象
zhangsan.high = 188; //通过对象访问类的公有数据成员
zhangsan.weight = 80; //通过对象访问类的公有数据成员
zhangsan.GetWeight(); //通过对象访问类的公有成员函数
zhangsan.GetHigh(); //通过对象访问类的公有成员函数
return 0;
}
private(私有类型)
private声明成员为私有访问,该级别的成员只能被它所在的类中的成员函数和该类的友元函数访问(限制访问)。
class Human
{
private: //声明类的私有数据成员
int high; //身高
int weight; //体重
public: //声明类的公有数据成员
void SetHight(int h)
{
high = h; //类的成员函数访问类的私有数据成员
}
void GetHigh()
{
cout << "身高:" << high << endl;//类的成员函数访问类的私有数据成员
}
void SetWeight(int w)
{
weight = w; //类的成员函数访问类的私有数据成员
}
void GetWeight()
{
cout << "体重:" << weight << endl;//类的成员函数访问类的私有数据成员
}
};
int main()
{
Human chen; //定义类的对象
//chen.high = hihi; //错误,不可以访问私有的数据成员
//chen.GetWeight = 66; //错误,不可以访问私有的数据成员
chen.SetHight(184);
chen.GetHigh();
chen.SetWeight(60);
chen.GetWeight();
return 0;
}
从上面的例子可以知道,private成员只能在类的成员函数里面使用。在类外,不能通过对象访问,比如chen.high=hihi;和chen.weigh=66;都是错误的。
protected(保护类型)
protected声明函数为保护成员。具有这个访问控制级别的成员,外界无法直接访问,只能倍它所在的类以及从该类派生出来的子类成员函数以及友元函数访问。它和private的区别就只在类继承时体现。
成员函数的实现方式
类的成员函数也是函数的一种,它与一般函数的区别在于,类的成员函数属于一个特定的类,是类的一个成员。
在使用类的成员函数时,要注意它的访问权限(私有or公有),以及它的作用域(类的成员函数能在什么范围内倍访问)。
类的成员函数有两种定义方式:直接在类中定义;在类中声明,类外定义。
- 在类中直接进行定义,这种方式一般用在代码比较少的成员函数中,并自动生成内联函数。
- 在类中进行函数声明,在类外对函数进行定义。这种情况通常在代码较多的成员函数上使用。在定义函数时,需要使用作用域符“::”表明函数所属的类。
返回类型 类名::函数名(参数列表)
{
//函数体
}
example:定义时钟类
class Clock
{
private:
int hour;//小时
int min;
int sec;
public:
void SetTime(int h, int m, int s);//类中声明,类外定义
void ShowTime()//类中定义函数
{
cout << hour << "时" << min << "分" << sec << "秒" << endl;
}
};//类的声明结束
void Clock::SetTime(int h, int m, int s)//定义成员函数
{
hour = h;
min = m;
sec = s;
}
int main()
{
Clock cc;
cc.SetTime(22, 3,6);
cc.ShowTime();
return 0;
}
程序执行结果如下:
成员函数内联(inline)
内联函数是C++为提高程序运行速度所做的一项改进。常规函数和内联函数之间的主要区别不在于编写方式,而在于C++编译器如何将它们组合到程序中。
当函数执行函数调用时,系统要为即将调用的函数创建栈空间(栈帧),保存现在正在执行的函数数据(保护现场),传递参数以及控制程序执行的跳转等操作,当调用的函数执行完成后又需要跳转到当前函数并恢复现在的数据(恢复现场),然后继续执行,这些操作都需要时间和空间开销。
C++内联(inline)函数提供了另一种选择,对于内联函数编译器将用函数代码替换函数调用,这样程序就无需跳到另一函数执行,执行完后在跳回来。因此内联函数的运行速度比常规函数稍快。
例如:求两个数的最大值
#include<iostream>
using namespace std;
inline int Max(int x, int y)//定义内联函数
{
return x > y ? x : y;
}
int main()
{
int a1=Max(1, 2);
int a2 = Max(6, 5);
int a3 = Max(a1, a2);
cout << "a1=" << a1 << endl;
cout << "a2=" << a2 << endl;
cout << "a3=" << a3 << endl;
return 0;
}
上面程序中,main()函数调用了3次内联函数Max(),在编译过程中展开类似下面的形式:
int a1=1>2?1:2;
int a2=6>5?6:5;
int a3=a1>a2?a1:a2;
程序员请求将函数作为内联函数时,编译器不一定满足这种要求,内联函数inline知识对编译器提出建议,但是有的编译器并没有启用或是实现这种特性。一般情况下,内联函数应该满足下面的要求:
- 函数不能出现循环
- 函数代码不超过3行
类中的内联函数
内联函数主要的应用场景就是类。如果类的成员函数非常简单(不超过三行代码),可以将成员函数定义在类中,这时,该函数自动成为内联函数,如果成员函数较复杂(超过3行,则在类中声明成员函数,而在类外定义)
内联和宏
inline是C++新增的特性,C语言使用预处理语句#define来实现宏,宏最常用的功能是让数字有自己的名字,而不是让它做函数该做的事情。下面是一个计算平方的宏:
#define SQUARE(x) x*x
宏仅仅是字符替换,如果要让宏执行类似函数的功能,需要使用内联函数
int a=1;
int b=SQUARE(2+3);//替换后的结果:int b=2+3*2+3;
int c=SQUARE(++a);//替换后的结果:int c=++a*++a;
成员函数重载
成员函数重载是指在同一个类里,有两个以上的函数具有相同的函数名。每种实现对应着一个函数体,但是形参的个数或者类型不同。(通俗来讲就是重载实现的载体是类的成员函数)
example:创建一个类,在类中定义3个名为subtract的重载成员函数,分别实现两个整数相减、两个实数相减和两个复数相减的功能。
struct Complex
{
double real;
double imag;
};
class Sub
{
public:
int subtract(int x, int y);
double subtract(double x, double y);
Complex subtract(const Complex& x, const Complex& y);
};
int Sub::subtract(int x, int y)
{
return x - y;
}
double Sub::subtract(double x, double y)
{
return x - y;
}
Complex Sub::subtract(const Complex &x,const Complex &y)
{
Complex c;
c.real = x.real - y.real;
c.imag = x.imag - y.imag;
return c;
}
int main()
{
int m = 30;
int n = 20;
double x = 34.5;
double y = 23.2;
Complex a = { 10,10 };
Complex b = { 5,5 };
Sub s;
cout << m << "-" << n << "=" << s.subtract(m, n) << endl;
cout << x << "-" << y << "=" << s.subtract(x, y) << endl;
Complex c = s.subtract(a, b);
cout << "(" << a.real << "+" << a.imag << "i)" << "-"
<< "(" << b.real << "+" << b.imag << "i)" << "="
<< "(" << c.real << "+" << c.imag << "i)" << endl;
return 0;
}
对象的创建和使用
用户自己定义的类可以被当作一个数据类型来使用,可以定义变量、数组、指针等,使用类来定义的变量通常被称为该类的对象。
对象的定义格式如下:
类名 对象名;
对象访问其成员
对象名.成员变量 //访问对象的成员变量
对象名.成员函数 //访问对象的成员函数
let us try:创建一个日期类
class Date
{
private:
int year;
int month;
int day;
public:
void SetDate(int y,int m,int d)
{
year = y;
month = m;
day = d;
}
void GetDate()
{
cout << year << "年" << month << "月" << day << "日" << endl;
}
};
int main()
{
Date date;
date.SetDate(2025, 6, 22);
date.GetDate();
return 0;
}
对象的指针访问其成员
对象的指针通过"->"访问它的成员变量和成员函数
对象的指针->成员变量
对象的指针->成员函数
int main()
{
Date date;
date.SetDate(2025, 6, 22);
Date* pd=&date;
pd->GetDate();
return 0;
}
对象的引用访问其成员
对象定义一个引用变量,他们共占同一段存储单元,因为引用是别名,不同的名字表示一个变量,所以完全可以用引用变量来访问对象中的成员。
类型 &引用变量名=对象名;
例如:通过对象的引用变量来访问对象的数据成员和成员函数。
#include<iostream>
using namespace std;
class Time //时间类
{
public:
int hour; //小时
int minute; //分钟
int second; //秒
void ShowTime(); //显示时间
};
void Time::ShowTime()
{
cout<<hour<<时""<<minute<<"分"<<second<<"秒"<<endl;
}
int main()
{
Time t1={23,9,9}; //创建Time对象t1
Time &t2=t1; //创建t2是t1的引用
t1.ShowTime(); //通过t1访问其成员函数
t1.ShowTime(); //通过引用变量访问对象的成员函数
return 0;
}
构造函数
构造函数是一种特殊的成员函数,专门用于构造新对象,并把数据赋值给它的成员。
构造函数在类里面的定义格式如下:
类名(参数列表)
{
函数体;
}
构造函数可以在类内也可在类外定义。在类外定义构造函数的形式如下:
类名::类名(形参列表)
{
函数体;
}
说明:
- 构造函数的名称必须与类名相同。
- 构造函数没有返回值类型,也不能指定为void
- 构造函数可以重载,即可以有多个构造函数
- 如果没有显式地定义构造函数,系统会自动生成一个默认的构造函数。这个构造函数不含参数,也不对数据成员进行初始化,只负责为对象分配存储空间。
- 如果显式地为类定义了构造函数,系统将不再为类提供默认构造函数
- 定义对象是,系统会自动调用构造函数
- 构造函数一般被定义为公有访问权限(否则无法构造对象)
构造函数的使用
#include<iostream>
using namespace std;
class Date
{
private:
int year;
int month;
int day;
public:
Date(int y,int m,int d);//构造函数
void Output();//输出函数
};
Date::Date(int y,int m,int d)
{
year=y;
month=m;
day=d;
}
void Date::Output()
{
cout<<year<<"-"<<month<<"-"<<day<<endl;
}
int main()
{
Date today(2025,6,6);
today.Output();
return 0;
}
默认构造函数
不需要提供参数的构造函数,可以由系统提供(不写任何构造函数)或程序提供(定义无参构造函数,或所有参数都有默认值的构造函数)
系统自动生成默认构造函数
如果我们没有编写任何构造函数,系统会自动生成默认构造函数,它值负责为对象分配存储空间,而不对数据进行初始化。
class Point
{
private::
int x;
int y;
pubilc:
void show()
{
cout<<"x="<<x<<",y="<<y<<endl;
}
};
int main()
{
Point p1;
p1.show();//输出的值没有初始化过,千万不要这样使用,值是随机值
return 0;
}
注意!系统虽然提供了默认的构造函数,但只是为了防止程序可以正常运行,并不是给我们来提供使用的,我们必须定义自己的构造函数。
自定义默认构造参数
定义无参的构造函数
calss Point
{
private:
int x;
int y;
public:
Point()
{
cout<<"自定义默认构造函数"<<endl;
x=0;
y=0;
}
void show()
{
cout<<"x="<<x<<",y="<<y<<endl;
}
};
int main()
{
Point p2;
p2.show();
return 0;
}
2.参数有默认值的构造函数
class Point
{
private:
int x;
int y;
public:
Point(int m = 0, int n = 10)
{
cout << "自定义构造函数,所有参数都有默认值" << endl;
x = m;
y = n;
}
void show()
{
cout << "x=" << x << ",y=" << y << endl;
}
};
int main()
{
Point p1;
p1.show();
Point p2 = { 100,200 };
p2.show();
return 0;
}
说明:
- 默认参数只能最上面给,不能多处给定(避免不一致)
- 带默认值的参数必须在最右面(从右往左给)
- 有默认参数时,注意避免重定义
上面三点和普通带默认值的函数一样
构造函数的重载
一个类可以定义多个构造函数,以便为类的对象提供不同的初始化放大,供用户选择使用。这些构造函数有相同的名字,但是参数列表不同。
example:构造函数重载
class Date
{
private:
int year;
int month;
int day;
public:
Date();
Date(int y,int m,int d);//构造函数
void show();
}
Date::Date()
{
year=2025;
month=6;
day=6;
}
Date::Date(int y,int m,int d)
{
year=y;
month=m;
day=d;
}
void Date::show()
{
cout<<year<<"-"<<month<<"-"<<day<<endl;
}
int main()
{
Date day();
Date today(2025,6,6);
day.show();
today.show();
return 0;
}
类定义时成员变量初始化
在C++11中允许在类定义是对成员变量初始化。
class A
{
public:
A(){}
void show()
{
cout<<"m_a"<<m_a<<endl;
cout<<"m_b"<<m_b<<endl;
}
private:
int m_a=10;//类定义时初始化
int m_b;//类定义时不初始化
};
int main()
{
A a;
a.show();
return 0;
}
如果在构造函数中也有赋值,以赋值的为准,这个就和普通变量一样,初始化的值会被后面的赋值覆盖。
class A
{
public:
A(int b = 0) :m_b(b)
{}
A(int a, int b) :m_a(a), m_b(b)
{}
void show()
{
cout << " m_a =" << m_a << endl;
cout << " m_b =" << m_b << endl;
}
private:
int m_a = 10;//类定义时初始化
int m_b;//没有初始化
};
int main()
{
A a;
cout << "a的数据:" << endl;
a.show();
A b{ 100 };
cout << "b的数据:" << endl;
b.show();
A c{ 1000,2000 };
cout << "c的数据:" << endl;
c.show();
return 0;
}
构造函数:
Date::Date(int y,int m,int d)
{
year=y;
month=m;
day=d;
}
初始化列表:
Date::Date(int y,int m,int d):year(y),month(m),day(d)
{}
利用构造函数定义(声明)对象的其他方式
class Date
{
private:
int year;
int month;
int day;
public:
Date(int y = 1970, int m = 1, int d = 1);
void show();
};
Date::Date(int y, int m, int d) :year(y), month(m), day(d)
{}
void Date::show()
{
cout << year << "-" << month << "-" << day << endl;
}
int main()
{
Date d1(2035, 6, 6);
Date d2;
d1.show();
d2.show();
Date d4 = { 2040,2,3 };
d4.show();
Date d5 = { 2050,3,4 };
d5.show();
Date d6 = { 2060,4,5 };
d6.show();
Date* d7 = new Date(2070, 5, 6);
d7->show();
//请考虑下面的定义对象是否能成功
//Date d8{};
//d8.show();
//Date* d9 = new Date();
//d9->show();
//Date* d10 = new Date{};
//d10->show();
return 0;
}