c++学习笔记第五天
一、c++中修饰类的const关键字
const 修饰类的成员变量,表示成员常量,不能被修改,同时它只能在初始化列表中赋值
(c11 中支持类中实始化)。可被 const 和非 const 成员函数调用,而不可以修改
class A
{
public:
A():iValue(199){}
private:
const int iValue;
};
4.14.2.常成员函数
4.14.2.1.const 修饰函数的意义
承诺在本函数内部不会修改类内的数据成员,不会调用其它非 const 成员函数
4.14.2.2.const 修饰函数位置
const 修饰函数放在,声明这后,实现体之前,大概也没有别的地方可以放了。
void dis() const
{}
4.14.2.3.const 构成函数重载
class A
{
public:
A():x(199),y(299){}
void dis() const //const
对象调用时,优先调用
{
//input();
不能调用 非 const 函数,因为本函数不会修改,无法保证所调的函数也不会修改
cout<<"x "<
cout<<"y "<
//y =200; const
修饰函数表示承诺不对数据成员修改。
}
void dis() //
此时构成重载,非 const 对象时,优先调用。
{
y = 200;
input();
cout<<"x "<
cout<<"y "<
}
void input()
{
cin>>y;
}
private:
const int x;
int y;
};
int main()
{
A a;
a.dis();
// const A a;
// a.dis();
return 0;
}
小结:
1,如果 const 构成函数重载,const 对象只能调用 const 函数,非 const 对象优先调
用非 const 函数。
2,const 函数只能调用 const 函数。非 const 函数可以调用 const 函数。
3,类体外定义的 const 成员函数,在定义和声明处都需要 const 修饰符。
4.14.3.常对象
const A a;
a.dis();
小结:
1,const 对象,只能调用 const 成员函数。
2,可访问 const 或非 const 数据成员,不能修改
二、c++中修饰类的static关键字
在 C++中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有
对象共用
。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共
享
不会破坏隐藏(相比全局变量的优点)的原则,保证了安全性还可以节省内存。
类的静态成员,属于类,也属于对象,但终归属于类。
4.15.1.类静态数据成员的定义及初始化
4.15.1.1.声明:
static 数据类型 成员变量; //在类的内部
4.15.1.2.初始化
数据类型 类名::静态数据成员 = 初值; //在类的外部
4.15.1.3.调用
类名::静态数据成员
类对象
.静态数据成员
4.15.1.4.案例
中国校园设计的“一塔湖图”
#include
using namespace std;
class School
{
public:
static void addLibBooks(string book)
{
lib += book;
}
public:
string tower;
string lake;
static string lib;
};
//
类外实始化
string School::lib = "Beijing lib:";
int main()
{
School a,b,c,d;
//static
数据成员,属于类,并不属于对象。
//存储于 data 区的 rw 段
cout<
//
类的方式访问,编译有问题,必须要初始化。
//在无对象生成的时候,亦可以访问。
School::lib = "China lib:";
cout<
//lib
虽然属于类,但是目的是为了实现类对象间的共享
//故对象也是可以访问的。
cout<
cout<
//
为了搞好图书馆的建设,提设 static 接口
School::addLibBooks("mao xuan");
cout<
return 0;
}
4.15.1.5.小结
1,static 成员变量实现了同簇类对象间信息共享。
2,static 成员类外存储,求类大小,并不包含在内。
3,static 成员是命名空间属于类的全局变量,存储在 data 区 rw 段。
4,static 成员使用时必须实始化,且只能类外初始化。
5,可以通过类名访问(无对象生成时亦可),也可以通过对象访问。
类静态成员函数的定义
为了管理静态成员,c++提供了静态函数,以对外提供接口。并静态函数只能访问静态成
员。
4.15.2.1.声明
static 函数声明
4.15.2.2.调用
类名::函数调用
类对象
.函数调用
4.15.2.3.案例
#include
using namespace std;
class Student
{
public:
Student(int n,int a,float s):num(n),age(a),score(s){}
void total()
{
count++;
sum += score;
}
static float average();
private:
int num;
int age;
float score;
static float sum;
static int count;
};
float Student::sum = 0;
int Student::count = 0;
float Student::average()
{
return sum/count;
}
int main()
{
Student stu[3]= {
Student(1001,14,70),
Student(1002,15,34),
Student(1003,16,90)
};
for(int i=0; i<3; i++)
{
stu[i].total();
}
cout<
return 0;
}
4.15.2.4.小结
1,静态成员函数的意义,不在于信息共享,数据沟通,而在于管理静态数据成员,
完成对静态数据成员的封装。
2,静态成员函数只能访问静态数据成员。原因:非静态成员函数,在调用时 this指
针时被当作参数传进。而静态成员函数属于类,而不属于对象,没有 this 指针。
三、c++中指向类成员的指针
指向类数据成员的指针
定义
<数据类型><类名>::*<指针名>
赋值&初始化
<数据类型><类名>::*<指针名>[=&<类名>::<非静态数据成员>]
指向非静态数据成员的指针在定义时必须和类相关联,在使用时必须和具体的对象
关联。
解用引
由于类不是运行时 存在的对象。因此,在使用这类指针时,需要首先指定类的一个对
象,然后,通过对象来引用指针所指向的成员。
<类对象名>.*<指向非静态数据成员的指针>
<
类对象指针>->*<指向非静态数据成员的指针>
案例
#include
using namespace std;
class Student
{
public:
Student(string n, int nu):name(n),num(nu){}
string name;
int num;
};
int main()
{
Student s("zhangsan",1002);
Student s2("lisi",1001);
// string *ps = &s.name;
// cout<< *ps<
string Student::*ps = &Student::name;
cout<
cout<
Student *pp = new Student("wangwu",1003);
cout<*ps<
return 0;
}
4.17.3.指向类成员函数的指针
定义一个指向非静态成员函数的指针必须在三个方面与其指向的成员函数保持一致:参数
列表要相同、返回类型要相同、所属的类型要相同
定义
<数据类型>(<类名>::*<指针名>)(<参数列表>)
赋值&初始化
<数据类型>(<类名>::*<指针名>)(<参数列表>)[=&<类名>::<非静态成员函数>]
解用引
由于类不是运行时存在的对象。因此,在使用这类指针时,需要首先指定类的一个对象,
然后,通过对象来引用指针所指向的成员。
(<类对象名>.*<指向非静态成员函数的指针>)(<参数列表>)
(<
类对象指针>->*<指向非静态成员函数的指针>)(<参数列表>)
案例
#include
using namespace std;
class Student
{
public:
Student(string n, int nu):name(n),num(nu){}
void dis()
{
cout<<"name "<
}
private:
string name;
int num;
};
int main()
{
Student s("zhangsan",1002);
Student s2("lisi",1001);
Student *ps = new Student("lisi",1003);
void
(Student::*pf)() = & Student::dis;
(s.*pf)();
(s2.*pf)();
(ps->*pf)();
return 0;
}
4.17.4.指向类成员指针小结:
与普通意义上的指针不一样。存放的是偏移量。
指向非静态成员函数时,必须用类名作限定符,使用时则必须用类的实例作限定符。指
向静态成员函数时,则不需要使用类名作限定符。
指向类静态数据成员的指针
指向静态数据成员的指针的定义和使用与普通指针相同,在定义时无须和类相关联,在
使用时也无须和具体的对象相关联。
指向类静态成员函数的指针
指向静态成员函数的指针和普通指针相同,在定义时无须和类相关联,在使用时也无须
和具体的对象相关联。
#include
using namespace std;
class A
{
public:
static void dis();
static int data;
};
void A::dis()
{
cout<
}
int A::data = 100;
int main()
{
int *p = & A::data;
cout<<*p<<endl;
void (*pfunc)() = &A::dis;
pfunc();
return 0;
}
四、友元
采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一
般定义为公有的,依此提供类与外界间的
通信接口。但是,有时需要定义一些函数,这些函数不
是类的一部分,但又需要
频繁地访问类的数据成员,这时可以将这些函数定义为该类的友元函数。
除了友元函数外,还有友元类,两者统称为友元。友元的作用是
提高了程序的运行效率(即减少
了类型和安全性检查及调用的时间开销),但它
破坏了类的封装性和隐藏性,使得非成员函数可
以访问类的私有成员。
友元可以是一个函数,该函数被称为
友元函数;友元也可以是一个类,该类被称为友元类。
5.1.同类对象间无私处
MyString::MyString(const MyString & other)
{
int len = strlen(other._str);
this->_str = new char[len+1];
strcpy(this->_str,other._str);
}
5.2.异类对象间有友员
友元目的本质,是让其它不属于本类的成员(全局函数,其它类的成员函数),成为类的成
员而具备了本类成员的属性。
5.2.1.友元函数
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它
不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字
friend,其格式如下:
friend 类型 函数名(形式参数);
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
5.2.1.1.全局函数作友元函数
#include
#include
using namespace std;
class Point
{
public:
Point(double xx, double yy)
{
x = xx;
y = yy;
}
void Getxy();
friend double Distance(Point &a, Point &b);
private:
double x, y;
};
void Point::Getxy()
{
cout << "(" << x << "," << y << ")" << endl;
}
double Distance(Point &a, Point &b)
{
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx*dx + dy*dy);
}
int main(void)
{
Point p1(3.0, 4.0), p2(6.0, 8.0);
p1.Getxy();
p2.Getxy();
double d = Distance(p1, p2);
cout << "Distance is" << d << endl;
return 0;
}
5.2.1.2.类成员函数作友元函数
#include
#include
using namespace std;
class Point;
class ManagerPoint
{
public:
double Distance(Point &a, Point &b);
};
class Point
{
public:
Point(double xx, double yy)
{
x = xx;
y = yy;
}
void Getxy();
friend double ManagerPoint::Distance(Point &a, Point &b);
private:
double x, y;
};
void Point::Getxy()
{
cout << "(" << x << "," << y << ")" << endl;
}
double ManagerPoint::Distance(Point &a, Point &b)
{
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx*dx + dy*dy);
}
int main(void)
{
Point p1(3.0, 4.0), p2(6.0, 8.0);
p1.Getxy();
p2.Getxy();
ManagerPoint mp;
float d = mp.Distance(p1,p2);
cout << "Distance is" << d<< endl;
return 0;
}
补充:
前向声明,是一种不完全型(forward declaration)声明,即只需提供类名(无需提供
类实现)即可。正因为是(incomplete type)功能也很有限:
(1)不能定义类的对象。
(2)可以用于定义指向这个类型的指针或引用。
(3)用于声明(不是定义),使用该类型作为形参类型或者函数的返回值类型。
5.2.2.友元类
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包
括私有成员和保护成员)。
当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义
友元类的语句格式如下:
friend class 类名;
其中:friend 和 class 是关键字,类名必须是程序中的一个已定义过的类。
例如,以下语句说明类
B 是类 A 的友元类:
class A
{
…
public:
friend class B;
…
};
经过以上说明后,类 B 的所有成员函数都是类 A 的友元函数,能存取类 A 的私有成员和
保护成员。
五、运算符重载
运算符重载的本质是函数重载。
6.1.重载入门
6.1.1.语法格式
重载函数的一般格式如下:
返值类型
operator 运算符名称(形参表列)
{
重载实体;
}
operator 运算符名称 在一起构成了新的函数名。比如
const Complex operator+(const Complex &c1,const Complex &c2);
我们会说,operator+ 重载了重载了运算符+。
6.1.2.友元重载
#include
using namespace std;
class Complex
{
public:
Complex(float x=0, float y=0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<","<<_y<<")"<
}
friend const Complex operator+(const Complex &c1,const Complex &c2);
private:
float _x;
float _y;
};
const Complex operator+(const Complex &c1,const Complex &c2)
{
return Complex(c1._x + c2._x,c1._y + c2._y);
}
int main()
{
Complex c1(2,3);
Complex c2(3,4);
c1.dis();
c2.dis();
// Complex c3 = c1+c2;
Complex c3 = operator+(c1,c2);
c3.dis();
return 0;
}
6.1.3.成员重载
#include
using namespace std;
class Complex
{
public:
Complex(float x=0, float y=0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<","<<_y<<")"<
}
friend const Complex operator+(const Complex &c1,const Complex &c2);
const Complex operator+(const Complex &another);
private:
float _x;
float _y;
};
const Complex operator+(const Complex &c1,const Complex &c2)
{
cout<<"
友元函数重载"<
return Complex(c1._x + c2._x,c1._y + c2._y);
}
const Complex Complex::operator+(const Complex & another)
{
cout<<"
成员函数重载"<
return Complex(this->_x + another._x,this->_y + another._y);
}
int main()
{
Complex c1(2,3);
Complex c2(3,4);
c1.dis();
c2.dis();
// Complex c3 = c1+c2;
// Complex c3 = operator+(c1,c2);
Complex c3 = c1+c2; //
优先调用成员函数重载??
c3.dis();
return 0;
}
备注:
关于返回值:
int a = 3;
int b = 4;
(a+b) = 100; 这种语法是错的,所以重载函数+的返回值加 const 是来修饰。
string a = “china”,b = “ is china”, c;
(c = a) = b;
此时的语法,是重载= 返回值不需加 const 。
所以重载运算符,不要破坏语意。
关于重载全局和成员
6.1.4.重载规则
(1)C++不允许用户自己定义新的运算符,只能对已有的 C++运算符进行重载。
例如,有人觉得 BASIC 中用“* *”作为幂运算符很方便,也想在 C++中将“* *”定
义为幂运算符,用“3* *5”表示 3
5,这是不行的。
(2)C++允许重载的运算符
C++中绝大部分运算符都是可以被重载的。
不能重载的运算符只有 4 个:
. 成员运算符
.* 成员对象选择符
:: 域解析运算符
?: 条件运算符
sizeof 类型大小运算符
前两个运算符不能重载是为了保证访问成员的功能不能被改变,域运算符合 sizeof 运
算符的运算对象是类型而不是变量或一般表达式,不具备重载的特征。
(3)重载不能改变运算符运算对象(即操作数)的个数。
如,关系运算符“>”和“<”等是双目运算符,重载后仍为双目运算符,需要两个参
数。运算符”+“,”-“,”*“,”&“等既可以作为单目运算符,也可以作为双目运算
符,可以分别将它们重载为单目运算符或双目运算符。
(4)重载不能改变运算符的优先级别。
例如”*“和”/“优先级高于”+“和”-“,不论怎样进行重载,各运算符之间的优
先级不会改变。有时在程序中希望改变某运算符的优先级,也只能使用加括号的方法强制改
变重载运算符的运算顺序。
(5)重载不能改变运算符的结合性。
如,复制运算符”=“是右结合性(自右至左),重载后仍为右结合性。
(6)重载运算符的函数不能有默认的参数
否则就改变了运算符参数的个数,与前面第(3)点矛盾。
(7)重载运算符的运算中至少有一个操作数是自定义类。
重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是
类对象(或类对象的引用)。
也就是说,参数不能全部是 C++的标准类型,以防止用户修改用于标准类型数据成员
的运算符的性质,如下面这样是不对的:
复制代码 代码如下:
int operator + (int a,int b)
{
return(a-b);
}
原来运算符+的作用是对两个数相加,现在企图通过重载使它的作用改为两个数相减。
如果允许这样重载的话,如果有表达式 4+3,它的结果是 7 还是 1 呢?显然,这是绝
对要禁止的。
(8)不必重载的运算符(= &)
用于类对象的运算符一般必须重载,但有两个例外,运算符”=“和运算符”&“不
必用户重载。
复制运算符”=“可以用于每一个类对象,可以用它在同类对象之间相互赋值。因为系
统已为每一个新声明的类重载了一个赋值运算符,它的作用是逐个复制类中的数据成员
地址运算符&也不必重载,它能返回类对象在内存中的起始地址。
(9)对运算符的重载,不应该失去其原有的意义
应当使重载运算符的功能类似于该运算符作用于标准类型数据时候时所实现的功能。
例如,我们会去重载”+“以实现对象的相加,而不会去重载”+“以实现对象相减的
功能,因为这样不符合我们对”+“原来的认知。
6.2.重载例举
6.2.1.双目运算符例举
6.2.1.1.双目运逄符重载格式
形式
L#R
全局函数
operator#(L,R);
成员函数
L.operator#(R)
6.2.1.2.重载+=实现
#include
using namespace std;
class Complex
{
public:
Complex(float x=0, float y=0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<","<<_y<<")"<
}
Complex& operator+=(const Complex &c)
{
this->_x += c._x;
this->_y += c._y;
return * this;
}
private:
float _x;
float _y;
};
int main()
{
// int a = 10, b = 20,c = 30;
// a += b;
// b += c;
// cout<<"a = "<
// cout<<"b = "<
// cout<<"c = "<
// Complex a1(10,0),b1(20,0), c1(30,0);
//
//(1)此时的+=重载函数返回 void
// a1 += b1;
// b1 += c1;
// a1.dis();
// b1.dis();
// c1.dis();
//----------------------------------------------------
// int a = 10, b = 20,c = 30;
// a += b += c;
// cout<<"a = "<
// cout<<"b = "<
// cout<<"c = "<
// Complex a1(10,0),b1(20,0), c1(30,0);
//
//(2)此时重载函数+=返回的是 Complex
// a1 += b1 += c1;
// a1.dis();
// b1.dis();
// c1.dis();
//----------------------------------------------------
int a = 10, b = 20,c = 30;
(a += b) += c;
cout<<"a = "<
cout<<"b = "<
cout<<"c = "<
Complex a1(10,0),b1(20,0), c1(30,0);
//
//(3)此时重载函数+=返回的是 Complex &
// 一定要注意在连等式中,返回引用和返回对象的区别
(a1 += b1) += c1;
a1.dis();
b1.dis();
c1.dis();
return 0;
}
operator-=
friend Complex& operator-=(Complex &c1, const Complex & c2)
{}
6.2.2.单目运算符例举
6.2.2.1.重载单目运算符格式
形式
#M 或 M#
全局函数
operator#(M)
成员函数
M.operator#()
6.2.2.2.重载-运算符
#include
using namespace std;
class Complex
{
public:
Complex(float x=0, float y=0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<","<<_y<<")"<
}
const Complex operator-(void) const
{
return Complex(-_x,-_y);
}
private:
float _x;
float _y;
};
int main()
{
int n = 10;
cout<
cout<<-n<
cout<
cout<<-(-n)<
// -n = 100;
Complex c(1,2);
Complex c2 = -c;
c2 = -(-c);
-c = Complex(3,4); //编译通不过
c.dis();
c2.dis();
c.dis();
return 0;
}
6.2.2.3.重载++(前++)
#include
using namespace std;
class Complex
{
public:
Complex(float x=0, float y=0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<","<<_y<<")"<
}
// Complex & operator++(void)
// {
// _x++;
// _y++;
// return *this;
// }
friend Complex & operator++(Complex& c);
private:
float _x;
float _y;
};
Complex & operator++(Complex& c)
{
c._x++;
c._y++;
return c;
}
int main()
{
int n = 10;
cout<
cout<<++n<
cout<
cout<<++++n<
cout<
Complex c(10,10);
c.dis(); //10 10
Complex c2=++c;
c2.dis(); //11 11
c.dis(); //11 11
c2 = ++++c;
c2.dis(); //13 13
c.dis(); //13 13
return 0;
}
6.2.2.4.重载++(后++)
#include
using namespace std;
class Complex
{
public:
Complex(float x=0, float y=0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<","<<_y<<")"<
}
// const Complex operator++(int)
//哑元
// {
// Complex t = *this;
// _x++;
// _y++;
// return t;
// }
friend const Complex operator++(Complex &c,int);
private:
float _x;
float _y;
};
const Complex operator++(Complex &c,int)
{
Complex t(c._x,c._y);
c._x++;
c._y++;
return t;
}
int main()
{
int n = 10;
cout<
cout<
cout<
// cout<<n++++<<endl; //13 后++表达式不能连用
cout<
Complex c(10);
c.dis();;
Complex c2 = c++;
c2.dis();
c.dis();;
// c2 = c++++;
// c2.dis();
c.dis();
return 0;
}
6.2.3.流输入输出运算符重载
函数形式
istream & operator>>(istream &,自定义类&);
ostream & operator<<(ostream &,
自定义类&);
通过友元来实现,避免修改 c++的标准库。
operator<< vs operator>>
class Complex
{
public:
Complex(float x=0, float y=0)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<","<<_y<<")"<
}
friend ostream & operator<<(ostream &os, const Complex & c);
friend istream & operator>>(istream &is, Complex &c);
//
成员的话必须保证左值为该类的对象
private:
float _x;
float _y;
};
ostream & operator<<(ostream &os, const Complex & c)
{
os<<"("<
return os;
}
istream & operator>>(istream &is, Complex &c)
{
is>>c._x>>c._y;
return is;
}
int main()
{
Complex c(2,3);
cout<
cin>>c;
cout<
return 0;
}
补充 MyString 类的流输入与输出
friend ostream & operator<<(ostream & os,const MyString &outStr);
friend istream & operator>>(istream &in, MyString & inStr);
ostream & operator<<(ostream & os,const MyString &outStr)
{
os<
return os;
}
istream & operator>>(istream &in, MyString & inStr)
{
delete [] inStr._str;
char buf[1024];
scanf(“%s”,buf); //scanf fgets in.getline(buf,1024);
int len;
len = strlen(buf);
inStr._str = new char[len+1];
strcpy(inStr._str,buf);
return in;
}
6.3.运算符重载小结
6.3.1.重载格式
6.3.2.不可重载的运算符
. (成员访问运算符)
.* (成员指针访问运算符)
:: (域运算符)
sizeof (长度运算符)
?: (条件运算符)
6.3.3.只能重载为成员函数的运算符
= 赋值运算符
[] 下标运算符
() 函数运算符
-> 间接成员访问
->* 间接取值访问
6.3.4.常规建议
6.3.5.友元还是成员?
引例
假设,我们有类 Sender 类和 Mail 类,实现发送邮件的功能。
Sender sender; Mail mail;
sender<< mail;
运算符 建议使用
所有的一元运算符 成员
+= -= /= *= ^= &= != %= >>= <<= 成员
其它二员运算符 非成员
sender 左操作数,决定了 operator<<为 Sender 的成员函数,而 mail 决定了
operator<<要作 Mail 类的友员。
#include
using namespace std;
class Mail;
class Sender
{
public:
Sender(string s):_addr(s){}
Sender& operator<<(const Mail & mail); //
成员
private:
string _addr;
};
class Mail
{
public:
Mail(string _t,string _c ):_title(_t),_content(_c){}
friend Sender& Sender::operator<<(const Mail & mail);
//
友元
private:
string _title;
string _content;
};
Sender& Sender::operator<<(const Mail & mail)
{
cout<<"Address:"<<_addr<
cout<<"Title :"<
cout<<"Content:"<
return *this;
}
int main()
{
Sender sender("guilin_wang@163.com");
Mail mail("note","meeting at 3:00 pm");
Mail mail2("tour","One night in beijing");
sender<
return 0;
}
结论:
1,一个操作符的左右操作数不一定是相同类型的对象,这就涉及到将该操作符函数定
义为谁的友元,谁的成员问题。
2,一个操作符函数,被声明为哪个类的成员,取决于该函数的调用对象(通常是左操
作数)。
3,一个操作符函数,被声明为哪个类的友员,取决于该函数的参数对象(通常是右操
作数)。
用类型转换构造函数进行类型转换
实现其它类型到本类类型的转化。
转换构造函数格式
class 目标类
{
目标类(const 源类 & 源类对象引用)
{
根据需求完成从源类型到目标类型的转换
}
}
特点:
转换构造函数,本质是一个构造函数。是
只有一个参数的构造函数。如有多个参数,
只能称为构造函数,而不是转换函数。
代码
#include
using namespace std;
class Point3D;
class Point2D
{
public:
Point2D(int x,int y)
:_x(x),_y(y){}
void dis()
{
cout<<"("<<_x<<","<<_y<<")"<
}
friend Point3D; //friend Point3D::Point3D( Point2D &p2);
private:
int _x;
int _y;
};
class Point3D
{
public:
Point3D(int x,int y,int z)
:_x(x),_y(y),_z(z){}
Point3D(Point2D &p)
{
this->_x = p._x;
this->_y = p._y;
this->_z = 0;
}
void dis()
{
cout<<"("<<_x<<","<<_y<<","<<_z<<")"<
}
private:
int _x;
int _y;
int _z;
};
void func(Point3D d3)
{ }
int main()
{
Point2D p2(1,2);
p2.dis();
Point3D p3(3,4,5);
p3.dis();
Point3D p3a = p2;
p3a.dis();
func(d2)
return 0;
}
explicit 关键字的意义
以显示的方式完成转化 static_cast<目标类> (源类对象)。否则会报错。
explicit Point3D(Point2D &p) //注:explicit 是个仅用于声明的关键字
{
this->_x = p._x;
this->_y = p._y;
this->_z = 0;
}
Point2D p2(1,2);
p2.dis();
Point3D p3a = static_cast (p2); //(Point3D)p2;
p3a.dis();
6.4.3.用类型转换操作符函数进行转换
类型转化函数格式
class 源类{
operator
转化目标类(void)
{
根据需求完成从源类型到目标类型的转换
}
}
特点
转换函数必须是类方法,转换函数无参数,无返回。
代码
#include
using namespace std;
class Point3D;
class Point2D
{
public:
Point2D(int x,int y)
:_x(x),_y(y){}
operator Point3D();
void dis()
{
cout<<"("<<_x<<","<<_y<<")"<
}
private:
int _x;
int _y;
};
class Point3D
{
public:
Point3D(int x,int y,int z)
:_x(x),_y(y),_z(z){}
void dis()
{
cout<<"("<<_x<<","<<_y<<","<<_z<<")"<
}
private:
int _x;
int _y;
int _z;
};
Point2D::operator Point3D()
{
return Point3D(_x,_y,0);
}
int main()
{
Point2D p2(1,2);
p2.dis();
Point3D p3(3,4,5);
p3.dis();
Point3D p3a = p2;
p3a.dis();
return 0;
}
6.4.4.小结
1,只有一个参数的类构造函数,可将参数类型转化为类类型。例如,将 int 类型的变
量赋给 obj 类型的对象。在构造函数中声明为 explicit 可以防止隐式转换,只允许显式转换。
2,称为转换函数的特殊类成员运算符函数,用于将类对象转换为其他类型。转换函数
为类成员函数。没有返回,没有参数。形如: operator typename(); typename 是对象将
被换成的类型。将类对象赋给 typname 变量时或将其强制转换为 typename 类型是,自动
被调用。
3,应用于构造及初始化,赋值,传参,返回等场合。