目录
- 四、类和对象的高级应用
6、对象成员
7、友元
8、友元函数
9、友元成员函数
10、友元类
11、运算符重载函数
- 四、类和对象的高级应用
6、对象成员
假如说有一个类, 类里面有一个数据成员是一个对象, 这个就叫做对象成员。
使用对象成员时需要注意的问题是构造函数的定义方式, 即类内部对象的初始化问题
class X
{
类名 1 成员名 1;
类名 2 成员名 2;
.....
};
一般来说, 类 X 的构造函数的定义形式为
X::X(参数表 0):成员名 1(参数表 1),.....,成员名 n(参数表 n)
{//构造函数体
}
当构造函数 X::X 时, 首先按各对象成员在类定义中的顺序依次调用它们的构造函数(即先初始化成员名 1, 再初始化成员名 2.....) , 对这些对象初始化, 最后再执行 X::X 的函数体;析构函数的调用顺序与此相反
//date.h
class DATE
{
private:
int year;
int month;
int day;
public:
DATE(int year, int month, int day);
void setYear(int year);
int getYear(void);
void setMonth(int month);
int getMonth(void);
void setDay(int day);
int getDay(void);
~DATE(void);
};
//stu.h
class STU
{
private:
int num;
public:
DATE birthday;
STU(int n, int year, int month, int day);
void setNum(int n);
int getNum(void);
~STU(void);
};
//date.cpp
DATE::DATE(int year, int month, int day)
{
cout << "date带参构造函数" << endl;
this->year = year;
this->month = month;
this->day = day;
}
//stu.cpp
STU::STU(int n, int year, int month, int day) :birthday(year,month,day)
{
cout << "stu带参构造函数" << endl;
num = n;
}
先构造对象成员再构造外层对象;先析构外层对象,再析构对象成员
在定义的时候加成员名 1(参数表 1),.....,成员名 n(参数表 n);在声明的时候不能加
7、友元
类的主要特点之一是数据隐藏, 即类的私有成员只能在类定义的范围内使用, 也就是说私有成员只能通过它
的成员函数来访问。
C++中的友元为数据隐藏这堵不透明的墙开了一个小孔, 外界可以通过这个小孔窥视类内部的秘密, 友元是一扇通
向私有成员的后门
友元可以分为: 友元函数、 友元成员、 友元类
8、友元函数
友元函数不是当前类的成员函数, 而是独立于当前类的外部函数, 但它可以访问该类的所有对象的成员, 包括私有成员和公有成员
在类定义中声明友元函数时, 需要在其函数名前面加上关键字 friend。 此声明可以放在公有部分, 也可以放在私有部分。
友元函数可以定义在类的内部, 也可以定义在类的外部。 注意: 无论友元函数定义在类内还是类外, 它都不是类的成员函数。
#include <iostream>
#include <cstring>
using namespace std;
class Girl{
private:
char *name;
int age;
public:
Girl(char *n,int d)
{
name = new char[strlen(n)+1];
strcpy(name,n);
age = d;
}
friend void disp(Girl &x); //声明为友元函数
~Girl()
{
delete name;
}
};
void disp(Girl &x) //定义友元函数
{
cout<<"girl\'s name is:"<<x.name<<",age:"<<x.age<<endl;
}
int main()
{
Girl e("Chen Xingwei",18);
disp(e); //调用友元函数
return 0;
}
友元函数虽然可以访问类对象的私有成员, 但它毕竟不是成员函数。 因此, 在类的外部定义友元函数时,不能像成员函数那样在函数名前面加上 “类名::”
友元函数一般是带有一个该类的入口参数。 因为友元函数不是类的成员函数, 所以它不能直接引用对象成员名称, 它必须通过入口参数传递进来的对象名或对象指针来引用该对象的成员。
当一个函数需要访问多个类时, 友元函数非常有用, 普通的成员函数只能访问其所属的类的数据成员,但是多个类的友元函数能够访问相应的所有类的数据成员
使用友元函数 , 一个友元函数可以访问两个类中的数据成员
#include <iostream>
#include <cstring>
using namespace std;
class Boy;//向前引用 在Girl中要使用Boy但是还未定义
class Girl{
private:
char *name;
int age;
public:
Girl(const char *n,int d)
{
name = new char[strlen(n)+1];
strcpy(name,n);
age = d;
}
friend void disp(Girl &x,Boy &y); //声明为友元函数
~Girl(){
delete name;
}
};
class Boy{
private:
char *name;
int age;
public:
Boy(const char *n,int d){
name = new char[strlen(n)+1];
strcpy(name,n);
age = d;
}
friend void disp(Girl &x,Boy &y); //声明为友元函数
~Boy(){
delete name;
}
};
void disp(Girl &x,Boy &y) //定义友元函数
{
cout<<"girl\'s name is:"<<x.name<<",age:"<<x.age<<endl;
cout<<"boy\'s name is: "<<y.name<<",age: "<<y.age<<endl;
}
int main()
{
Girl e("Chen Xingwei",18);
Boy ob("lilei",19);
disp(e,ob); //调用友元函数
return 0;
}
友元函数 disp 必须定义在类 Girl 和类 Boy 的下面, 或者是定义在最后那个类( Boy) 里面, 否则因无法使用类的数据成员, 而导致编译报错。
在某些情况下, 如运算符重载时需要用到友元。 但是友元函数破坏了数据的隐蔽性, 降低了程序的可维护性, 这与面向对象的程序设计思想是背道而驰的, 因此使用友元函数应该谨慎
9、友元成员函数
除了一般的函数可以作为某个类的友元外, 一个类的成员函数也可以作为另一个类的友元, 这种成员函数不仅可以访问自己所在的类对象中的私有成员和公有成员, 还可以访问 friend 声明语句所在类对象中的私有成员和公有成员, 这样能使两个类相互合作、 协调工作, 完成某一任务。
#include <iostream>
#include <cstring>
using namespace std;
class Boy;//向前引用
//向前引用只是说明功能在, 但是不知道有什么数据成员及成员函数
class Girl{
private:
char *name;
int age;
public:
Girl(const char *name,int age){
this->name = new char[strlen(name)+1];
strcpy(this->name,name);
this->age = age;
}
void girl_print(Boy &boy);//这个地方必须是类内声明, 类外定义, 否则不能用 boy 的数据成员
~Girl(){
delete name;
}
};
class Boy{
private:
char *name;
int age;
public:
Boy(const char *name,int age){
this->name = new char[strlen(name)+1];
strcpy(this->name,name);
this->age = age;
}
friend void Girl::girl_print(Boy &boy);//声明为友元函数
~Boy(){
delete name;
}
};
void Girl::girl_print(Boy &boy)//类内声明, 类外定义
{
cout<<"girl.name= "<<this->name<<endl;
cout<<"girl.age= "<<this->age<<endl;
cout<<"boy.name= "<<boy.name<<endl;
cout<<"boy.age= "<<boy.age<<endl;
}
int main()
{
Girl e("Chen Xingwei",18);
Boy ob("lilei",19);
e.girl_print(ob);
return 0;
}
10、友元类
class Y{
//......
};
class X{
//......
friend Y;
//......
};
类 Y 就是类 X 的友元类。 在 Y 类中可以访问类 X 的数据;当一个类被声明为另一个类的友元时, 它的所有成员函数都成为另外一个类的友元函数, 这就意味着友元的类中所有成员函数都可以访问另一个类的私有成员。
#include <iostream>
#include <cstring>
using namespace std;
class Boy;//向前引用
//向前引用只是说明功能在, 但是不知道有什么数据成员及成员函数
class Girl{
private:
char *name;
int age;
public:
Girl(char *name,int age){
this->name = new char[strlen(name)+1];
strcpy(this->name,name);
this->age = age;
}
void girl_print(Boy &boy);
~Girl(){
delete name;
}
};
class Boy{
private:
char *name;
int age;
public:
Boy(char *name,int age){
this->name = new char[strlen(name)+1];
strcpy(this->name,name);
this->age = age;
}
friend class Girl;
//声明 Girl 类是 Boy 类的友元类, 则在 Girl 类中的成员函数就可以访问 Boy 类中的数据了
~Boy(){
delete name;
}
};
void Girl::girl_print(Boy &boy)
{
cout<<"girl.name= "<<this->name<<endl;
cout<<"girl.age= "<<this->age<<endl;
cout<<"boy.name= "<<boy.name<<endl;
cout<<"boy.age= "<<boy.age<<endl;
}
int main()
{
Girl e("Chen Xingwei",18);
Boy ob("lilei",19);
e.girl_print(ob);
return 0;
}
11、运算符重载函数
运算符重载使复杂函数的理解更直观, 程序更加简单易懂
运算符重载函数的形式是:
返回值类型 operator 运算符符号(参数说明)
{//函数体内部实现}
至少有一个参数是自定义类型(数组, 类);如果是单目运算符, 只传一个参数;如果是双目运算符, 传两个参数
C++规定的不能重载的运算符:::、 *、 sizeof、 .、 ?:
常见运算符重载函数的使用
一种是作为类的友元函数进行使用
class MyString{
private:
char *str;
public:
MyString(char *str);
void display(void);
friend void append(MyString &temp1,MyString &temp2);
friend void operator +(MyString &temp1,MyString &temp2);
~MyString();
};
void operator +(MyString &temp1,MyString &temp2)
{
//append函数和此函数的函数体一样,二者功能一样;都是字符串追加
char *tmp;
tmp=new char[strlen(temp1.str)+strlen(temp2.str)+1];
strcpy(tmp,temp1.str);
strcat(tmp,temp2.str);
delete temp1.str;
temp1.str=NULL;
temp1.str=tmp;
}
int main()
{
MyString ob1("hello");
ob1.display();
MyString ob2("world");
ob2.display();
//append(ob1,ob2);
//ob1.display();
ob1+ob2;
//也可以operator +(ob1,ob2);这样调用
ob1.display();
return 0;
}
一种是作为类的成员函数进行使用
class Internet{
private:
char *name;
char *url;
public:
Internet(const char *name,const char *url);//构造函数
Internet(Internet &ob);//拷贝构造函数
Internet & operator =(const Internet &temp)
{
delete []this->name;
this->name=new char[strlen(temp.name)+1];
delete []this->url;
this->url=new char[strlen(temp.url)+1];
strcpy(this->name,temp.name);
strcpy(this->url,temp.url);
cout<<"= 运算符重载"<<endl;
return *this;
}
void display();
~Internet();//析构函数
};
ob3=ob1;//使用的是 = 运算符重载
//ob3.operator =(ob1);//这种方法调用也是可以的, 重载运算符原型