this指针(this表示当前对象)
显式引用 this指针的三种情况
(1)在类的非静态成员函数中返回类对象本身或对象的引用的时候,直接使用 return *this,返回本对象的地址时,return this。
#include <iostream>
#include <string>
using namespace std;
class Person{
public:
Person(string n, int a) {
name = n; //这里的 name 等价于this->name
age = a; //这里的 age 等价于this->age
}
int get_age(void) const{ return age; }
Person& add_age(int i) {age += i; return *this; //返回值为当前对象的引用 }
private:
string name;
int age;
};
int main()
{
Person Li("Li", 20);
cout<<"Li age = "<< Li.get_age()<<endl;
cout<<"Li add age = "<< Li.add_age(1).get_age()<<endl;
//增加1岁的同时,可以对新的年龄直接输出,Li返回值为当前对象的引用();
return 0;
}
程序执行结果为:
Li age = 20
Li add age = 21
(2)当参数与成员变量名相同时,如this->x = x,不能写成x = x。
#include <iostream>
using namespace std;
class Point
{
public:
int x;
Point ():x(0){}
Point (int a){ x=a; }
void print(){ cout<<"x = "<<x<<endl; }
void set_x(int x){ x = x; }
};
int main(){
Point pt(5);
pt.set_x(10);
pt.print();
return 0;
}
程序执行结果为:
x = 5
若将set_x函数改为:
void set_x(int x) { this->x = x; }
程序执行结果为:
x = 10
(3)避免对同一对象进行赋值操作,判断两个对象是否相同时,使用this指针。
#include <iostream>
using namespace std;
class Location
{
int X,Y; //默认为私有的
public:
void init(int x,int y) { X =x; Y = y;};
void assign(Location& pointer);//
int GetX(){ return X; }
int GetY(){ return Y; }
};
void Location::assign(Location& pointer)
{
if(&pointer!=this) //同一对象之间的赋值没有意义,所以要保证pointer不等于this
{ X=pointer.X; Y=pointer.Y; }
}
int main(){
Location x;
x.init(5,4);
Location y;
y.assign(x);
cout<<"x.X = "<< x.GetX()<<" x.Y = "<<x.GetY();
cout<<"y.X = "<< y.GetX()<<" y.Y = "<<y.GetY();
return 0;
}
复制构造函数
语法形式
类名 :: 类名(const 类名 & 引用名 , …);
(形参)参数是同类对象,
要求有一个类类型的引用参数。
浅复制:
在用一个对象初始化另一个对象时,只复制了数据成员,而没有复制资源,即:对于复杂类型的数据成员只复制了存储地址而没有复制存储内容
深复制:
一个对象初始化另一个对象时,不仅复制了数据成员,也复制了资源
定义:类名::类名([const] 类名 &对象名);
类的其他成员
常成员
静态成员
友元(破坏了封装,不建议使用)
1 常成员
(1)常数据成员
常数据成员是指数据成员在实例化被初始化后,其值不能改变。
如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化,而任何其他函数都不能对该成员赋值。
#include<iostream>
using namespace std;
class Mclass
{ public :
int k;
const int M; //说明常数据成员
Mclass() : M(5) { } //用初始式对常数据成员赋值
void testFun()
{ //M++; //错误,不能在成员函数中修改常数据成员
k++; //可以修改一般数据成员
}
} ;
int main()
{ Mclass t1, t2;
t1.k=100;
//t1.M=123; //错误,不能在类外修改常数据成员
cout<<"t1.k="<<t1.k<<'\t'<<"t1.M="<<t1.M<<endl;
t2.k=200; t2.testFun();
cout<<"&t1.M="<<&t1.M<<endl;
cout<<"t2.k="<<t2.k<<'\t'<<"t2.M="<<t2.M<<endl;
cout<<"&t2.M="<<&t2.M<<endl;
}
#include<iostream>
#include<cstring>
using namespace std;
struct Date { int year, month, day ; }; //结构
class Student
{ public:
Student (int y,int m,int d, int num=0, string name="no name");
void PrintStudent()const; //常成员函数
private:
const int code; //常数据成员
string name;
Date birthday; //结构数据成员(数据对象)
};
(2)常对象:
说明形式如下:
类名 const 对象名[(参数表)];
或者
const 类名 对象名[(参数表)];
在定义常对象时必须进行初始化,而且不能被更新。
说明:
(1)C++不允许直接或间接更改常对象的数据成员。
(2)C++规定常对象只能调用它的常成员函数、静态成员函数、构造函数(具有公有访问权限)。
class T_class
{ public:
int a, b;
T_class( int i, int j ) {
a=i; b=j;
}
} ;
int main()
{ const T_class t1( 1, 2 );
T_class t2( 3, 4 );
//t1.a=5;
//t1.b=6;不能更改
t2.b=8;
t2.a=7;
cout<<"t1.a="<<t1.a<<'\t'<<"t1.b="<<t1.b<<endl;
cout<<"t2.a="<<t2.a<<'\t'<<"t2.b="<<t2.b<<endl;
}
(3)常成员函数:
在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数(对数据成员只读不写)
格式如下:
类型说明符 函数名(参数表) const;
const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const。
常成员函数不能更新对象的数据,也不能调用非const修饰的成员函数(静态成员函数、构造函数除外)
(只读不写)。
void constFun ( ) const
{ x ++ ; y ++ ; }//非法
2,静态成员:(即类成员)
静态数据成员为同类对象共享。
静态成员函数与静态数据成员协同操作
(1)静态数据成员:
公有访问权限的静态成员,可以通过下面的形式进行访问:
类名::静态成员名字
对象名.静态成员名字
对象指针->静态成员名字
在静态成员函数内部,直接访问。
静态数据成员声明及初始化:
类型 类名::静态数据成员[=初始化值]; //必须进行声明
不能在成员初始化列表中进行初始化
class X { char ch ; static int s ; …... };
int X :: s = 0 ;
X a , b , c , d ;
如果未进行初始化,则编译器自动赋初值(默认值是0)
例题:
某商店经销一种货物,货物成箱进,成箱卖出,购进和卖出都是以重量为单位(每箱的重量不同),商店需要记录下存货的总重量。
分析:
定义一个货物类,表示一箱货物,类中包含
私有成员 weight
一个静态数据成员total_weight;
定义in函数,表示进货,进货时total_weight的值增加
定义out函数,表示出货,出货时total_weight的值减少
#include <iostream>
using namespace std;
class Goods{
int weight;
public:
static int total_weight;//类对象
Goods(int x):weight(x){}
void in() {total_weight=total_weight+weight; }
void out(){total_weight=total_weight-weight; }
void display_store(){ cout<<total_weight<<endl;}
};
int Goods::total_weight=0;
void display_store(){ cout<<Goods::total_weight<<endl;}
int main(){
Goods g1(10),g2(20);
g1.in();
g2.in();
g1.display_store();
g2.display_store();
display_store();
g1.out();
g1.display_store();
display_store();
return 0;
}
(2)静态成员函数
静态成员函数和静态数据成员都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。
静态成员函数没有this指针,只能对静态数据操作
定义静态成员函数的格式如下:
static 返回类型 静态成员函数名(参数表);
调用公有静态成员函数的一般格式:
类名::静态成员函数名(实参表)
对象. 静态成员函数名(实参表)
对象指针->静态成员函数名(实参表)
说明:
(1)静态成员函数在类外定义时不用static前缀。
(2)静态成员函数主要用来访问同一类中的静态数据成员。
(3) 私有静态成员函数不能在类外部或用对象访问。
(4)可以在建立对象之前处理静态数据成员。
(5)编译系统将静态成员函数限定为内部连接(在其他文件中不可见)。
(6)静态成员函数中是没有this指针的。
(7)静态成员函数不访问类中的非静态数据成员。如有需要,只能通过对象名(或指向对象的指针)访问该对象的非静态成员。
3.友元函数(破坏封装)
(1)友元函数
如果在本类(类A)以外的其他地方定义了一个函数(函数B)
类体中用friend对其(函数B)进行声明,此函数就称为本类(类A)的友元函数。
#include<iostream>
using namespace std;
class Boat{
int weight;
public:
Boat(){weight=0;}
Boat(int w):weight(w){}
friend void display_weight(Boat &a);
};
void display_weight(Boat &a){
cout<<a.weight<<endl;}
int main(){
Boat b(100);
display_weight(b);
return 0;
}
(2)友元类
若F类是A类的友元类,则F类的所有成员函数都是A类的友元函数
声明:friend class 类名;
#include<iostream>
using namespace std ;
class A
{ friend class B ;
public :
void Display()
{ cout << x << endl ; } ;
private :
int x ;
} ;
class B
{ public :
void Set ( int i ) { Aobject . x = i ; }
void Display () { Aobject . Display () ; }
private :
A Aobject ;
} ;
int main()
{ B Bobject ;
Bobject . Set ( 100 ) ;
Bobject . Display () ;
}
4.类的组合
当一个类中含有已经定义的类类型成员,带参数的构造函数对数据成员初始化,须使用初始化语法形式。
构造函数 ( 形参表 ) : 对象成员1(形参表 ) , … , 对象成员n (形参表 ) ;
#include<iostream>
using namespace std;
class A
{ public:
A(int x):a(x){ }
int a ;
};
class B
{ public:
B( int x, int y ) : aa(x) { b = y ; }
//类类型初始化列表
//成员对象的构造函数调用次序和成员对象在类中的说明次序一致,与它们在成员初始化列表中出现的次序无关
void out() { cout<<"aa = "<<aa.a<<endl<<"b = "<<b<<endl ; }
private:
int b ;
A aa ;
} ;
int main()
{ B objB( 3, 5 ) ;
objB.out() ;
}
class Score
{
public:
Score(float c, float e, float m );
Score();
void show();
void modify(float c, float e, float m);
private:
float computer;
float english;
float mathematics;
};
class Student
{
private:
string name;
string stu_no;
Score score1;
public:
Student(string name1, string stu_no1, float s1, float s2, float s3):score1(s1,s2,s3){
name=name1;
stu_no=stu_no1;
}
~Student();
void modify(string name1, string stu_no1, float s1, float s2, float s3);
void show();
};