3.1构造函数
特点:
(1)构造函数的名字与它的类名必须相同。
(2)它没有类型,与不返回值
(3)它可以带参数,也可以不带参数。
#include <iostream>
using namespace std;
class Time{
public:
Time(){//构造函数
hour = 0;
minute = 0;
sec = 0;
}
//此处也可以只写Time();
void set_time();
void show_time();
private:
int hour;
int minute;
int sec;
};
//在类外构造函数
/*
Time::Time(){
hour = 0;
minute = 0;
sec = 0;
}
*/
int main(){
Time t1;
t1.set_time();
t1.show_time();
Time t2;
t2.show_time();
return 0;
}
void Time::set_time(){
cin >> hour;
cin >> minute;
cin >> sec;
}
void Time::show_time(){
cout << hour << ":" << minute << ":" << sec << endl;
}
构造函数没有返回值,因此不需要在定义中声明类型。
构造函数可以带参数:
构造函数名(类型 形参1,类型 形参2);
定义对象格式:
类名 对象名(实参1,实参2);
#include <iostream>
using namespace std;
class Box{
public:
Box(int, int, int);
int volume();
private:
int height;
int width;
int length;
};
Box::Box(int h, int w, int len) {// 长方体构造函数
height = h;
width = w;
length = len;
}
int Box::volume() {// 计算长方体的体积
return (height * width * length);
}
int main(){
Box box1(12, 25, 30); // 定义对象box1
cout << " box1体积=" << box1.volume() << endl;
Box box2(15, 30, 21); // 定义对象box2
cout << " box2体积= " << box2.volume() << endl;
return 0;
}
也可以用形参初始化表的构造函数:
Box::Box(int h, int w, int len) : height(h), width(w), length(len) {}
构造函数也可以重载,在一个类中可以有多个重名的构造函数,但是参数个数、类型各不相同。
Box box1;
Box box2(1,1,1);
构造函数形参表可以带默认值,形参名也可以忽略
Box(int =10,int =10,int =10);
3.2 析构函数
特殊的成员函数,作用与构造函数相反,收回对象占用的内存空间。
执行时机:
(1)函数结束时
(2)static局部对象、全局对象要等main结束或者exit命令
(3)new建立的动态对象,用delete时自动析构
#include <iostream>
#include <string>
using namespace std;
class Student{
public:
Student(int n, string nam, char s){
num = n;
name = nam;
sex = s;
cout << "Constructor called." << endl;
}
~Student(){
cout << "Destructor called." << endl;
}
//以~符号开始后面跟类名,没有数据类型、返回值、形参,但是可以执行其他操作
void display(){
cout << "num:" << num << endl;
cout << "name:" << name << endl;
cout << "sex:" << sex << endl
<< endl;
}
private:
int num;
string name;
char sex;
};
int main(){
Student stud1(10010, "Wang_li", 'f');
stud1.display();
Student stud2(10011, "Zhang_fun", 'm');
stud2.display();
return 0;
}
3.3调用析构函数和构造函数的顺序
先调用构造函数,最后调用析构函数。
先构造的后析构(栈,先进后出)
自定义局部自动对象,在函数调用结束时析构。
静态局部对象或全局变量,在主函数结束或调用exit函数时析构。
例如:
Void fn(){
student st1; // 定义局部自动对象
static student st2; // 定义静态局部对象
}
//对象st1是每次调用函数fn时调用构造函数在函数fn结束时调用析构函数。
//对象st2是第一次调用函数fn时调用构造函数在函数fn结束时并不调用析构函数,在到主函数结束时才调用析构函数。
3.4对象数组
Student std[50];
//可以这样构造函数
Student::Student(int =1001,int =18,int =60);
在建立对象数组时,分别调用构造函数,对每个对象初始化。每个元素的实参用括号括起来,实参的位置与构造函数形参的位置一一对应,不会混淆。
student std[3] = {
student(1001, 18, 87),
student(1002, 19, 76),
student(1003, 18, 80)}; // 构造函数带实参
举个栗子:
#include <iostream>
using namespace std;
class Box{
public:
Box(int h = 10, int w = 12, int len = 15) : height(h), width(w), length(len) {} // 带默认参数值和参数表
int volume();
private:
int height;
int width;
int length;
};
int Box::volume(){
return (height * width * length);
}
int main(){
Box a[3] = {Box(10, 12, 15),
Box(15, 18, 20),
Box(16, 20, 26)};
cout << "a[0]的体积是 " << a[0].volume() << endl;
cout << "a[1]的体积是 " << a[1].volume() << endl;
cout << "a[2]的体积是 " << a[2].volume() << endl;
return 0;
}
// 每个数组元素是一个对象
3.5对象指针
指向对象的指针:
类名 *变量名表
Time *pt; // 定义pt是指向Time类对象的指针
Time t1; // 定义Time类对象t1
pt = &t1; // 将对象t1的地址赋予pt
//访问方式:
(*pt).hour
pt->hour(*pt)
.show_time()
pt->show_time()
指向对象公有数据成员的指针:
定义:数据类型 *指针变量名
地址:&对象名.成员名
Time t1;
int *p1; // 定义一个指向整型数据的指针变量
p1 = &t1.hour; // 假定hour是公有成员
cout << *p1 << endl;
指向对象成员函数的指针:
定义:数据类型(类名::*变量名)(形参表);
地址: &类名::成员函数名
赋初值:指针变量名 = &类名::成员函数名;
指针变量调用成员函数:(对象名.*指针变量名)([实参表]);
举个栗子:
#include <iostream>
using namespace std;
class Time{
public:
Time(int, int, int);
int hour;
int minute;
int sec;
void get_time();
};
Time::Time(int h, int m, int s){
hour = h;
minute = m;
sec = s;
}
void Time::get_time(){
cout << hour << ":" << minute << ":" << sec << endl;
}
int main(){
Time t1(10, 13, 56);
int *p1 = &t1.hour; // 定义指向成员的指针p1
cout << *p1 << endl;
t1.get_time(); // 调用成员函数
Time *p2 = &t1; // 定义指向对象t1的指针p2
p2->get_time(); // 用对象指针调用成员函数
void (Time::*p3)(); // 定义指向成员函数的指针
p3 = &Time::get_time; // 给成员函数的指针赋值
(t1.*p3)(); // 用指向成员函数的指针调用成员函数
return 0;
}
运行结果:
10 // *p1的值
10:13:56 // t1.get_time(); 的执行结果
10:13:56 // p2->get_time(); 的执行结果
10:13:56 // (t1.*p3)(); 的执行结果
this指针:
C++ 通过编译程序,在对象调用成员函数时,把对象的地址赋予this 指针,用this 指针指向对象,实现了用同一个成员函数访问不同对象的数据成员。
int Box ::volume(*this){
return (this->height * this->width * this->length);
}
可省略this
3.6公用数据的保护
格式:
const 类名 对象名(实参表);
类名 const 对象名(实参表);
指向常对象的指针:
格式:类名 * const 指针变量名 = 对象地址
Time t1(10, 12, 15),t2;
Time *const p1 = &t1;
此后的程序中不能修改p1。
对象的常引用:
格式:const 类名 &形参对象名
#include <iostream>
using namespace std;
class Time{
public:
Time(int, int, int);
//此处可改为
//void fun(const int &t);
//则不能改变实惨t1的值
void fun(int &t)
{
hour = t;
t = 18;
}
int hour;
int minute;
int sec;
};
Time::Time(int h, int m, int s){
hour = h;
minute = m;
sec = s;
}
int main(int argc, char *argv[]){
int x = 15;
Time t1(10, 13, 56);
t1.fun(x);
cout << t1.hour << endl;
cout << x << endl;
return 0;
}
3.7 对象的动态建立和释放
格式: new 类名
Box *pt;
pt = new Box;
//如分配内存成功,就可以用指针变量pt访问动态对象的数据成员。
cout<< pt->height;
cout << pt->volume();
释放格式: delete 指针变量
3.8对象的赋值和复制
赋值格式: 对象1=对象2
注意:
(1)对象的赋值只对数据成员操作。
(2)数据成员中不能含有动态分配的数据成员。
复制格式:
类名 对象2(对象1);
类名 对象2=对象1,对象3=对象1,…;
Box ::Box(const Box &b){
height = b.height;
width = b.width;
length = b.length;
}
3.9静态成员
静态数据成员格式:static 类型 数据成员名
几点说明:
(1)只能类外初始化。
(2)程序开始时分配内存空间,结束时释放
(3)作用域为类的作用域,访问格式为 类名::静态成员名
静态成员函数格式:static 类型 成员函数(形参表){…}
静态成员函数不带this指针,所以必须要用对象名.成员名访问
#include <iostream>
using namespace std;
class Point{
private: // 私有数据成员
int X, Y;
static int countP;
public: // 外部接口
Point(int xx = 0, int yy = 0){
X = xx;
Y = yy;
countP++;
}
Point(Point &p); // 拷贝构造函数
int GetX() { return X; }
int GetY() { return Y; }
static void GetC(){
cout << " Object id=" << countP << endl;
}
};
Point::Point(Point &p){
X = p.X;
Y = p.Y;
countP++;
}
int Point::countP = 0;
int main(){
Point A(4, 5); // 声明对象A
cout << "Point A," << A.GetX() << "," << A.GetY();
A.GetC(); // 输出对象号,对象名引用
Point B(A); // 声明对象B
cout << "Point B," << B.GetX() << "," << B.GetY();
Point::GetC(); // 输出对象号,类名引用
return 0;
}
输出结果:
Point A,4,5 Object id=1
Point B,4,5 Object id=2
3.10友元
在A类外定义函数,如果是A的友元,则可以访问A中的所有成员(老板是下属的友元)
格式:
friend 类型 类1::成员函数x(类2 &对象);
friend 类型 函数y(类2 &对象);
x与y是友元函数
#include <iostream>
#include <math.h>
using namespace std;
class TPoint{
private:
double x, y;
public:
TPoint(double a, double b){
x = a;
y = b;
cout <<"点:("<<x<<", "<<y<<") "<<endl;
}
friend double distance(TPoint & a, TPoint & b){ // 通过对象访问私有数据成员
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
};
/*double distance(TPoint &a, TPoint &b)
{ //通过对象访问私有数据成员
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}*/
int main(int argc, char* argv[]){
TPoint myp1(2.1,1.3), myp2(5.4,6.5);
cout<<"两点之间的距离为";
cout<<distance(myp1,myp2)<<endl;
return 0;
}
友元成员函数:
格式:friend 类型 类名::函数名(形参表)
friend void Time::display(const Date &);
/*友元是单向的,此例中声明Time的成员函数display是Date类的友元,允许它访问Date类的所有成员。但不等于说Date类的成员函数也是Time类的友元。*/
友元类:
在B类中声明A类为友元类的格式:
friend A;
3.11类模板
格式:template <class 类型参数名>
class 类模板名{…}
template <class numtype>
class Compare{
private:
numtype x, y;
public:
Compare(numtype a, numtype b) {// 构造函数
x = a;
y = b;
}
numtype max(){
return (x > y) ? x : y;
}
numtype min(){
return (x < y) ? x : y;
}
};
在类模板外定义成员函数格式:
类型参数 类模板名<类型参数>::成员函数名(形参表) {…}
template <class numtype>
class Compare
{
public:
Compare(numtype a, numtype b){
x = a;
y = b;
}
numtype max();
numtype min();
private:
numtype x, y;
};
numtype Compare<numtype>::max(){
return (x > y) ? x : y;
}
numtype Compare<numtype>::min(){
return (x < y) ? x : y;
}