C++第十天

1.多态基础

1.1.约分实现代码

#include <iostream>
using namespace std;

class Fract
{
	int n;
	int d;
public:
	Fract():n(0),d(1){}
	Fract(int an,int ad):n(an),d(ad)
	{
			//reduce定义在后面,在未定义时竟然可以使用???
			//解释:编译器在处理类时先看所有函数的声明,处理完后才会看函数体中内容
			//所以编译器还是先看到了声明,后看到使用
			reduce();	
	}
	void reduce()
	{
			if(d<0)//分母小于0
			{
				d=-d;
				n=-n;
			}
			else if(d==0)//分母等于0
			{
				cout<<"d==0!!"<<endl;	
			}
			int absn = (n<0)?-n:n;
			for(int i=d;i>1;i--)
			{
				if(absn%i==0&&d%i==0)	
				{
					n/=i;
					d/=i;	
					break;
				}
			}
	}
	void show()
	{
		cout<<n	<<'/'<<d<<endl;
	}
	double value()
	{
		return (double)n/d;	
	}
};
//子类继承父类
class Dai:public Fract
{
	int i;
public:
	Dai():i(0){} //无参构造函数
	Dai(int ai,int an,int ad) //有参构造函数
	:i(ai),Fract(an,ad){}//初始化列表,父类的参数初始化交给父类去处理	
	void show() //子类和父类中有同名函数,子类中调用父类同名函数调用方法
	{
		cout<<i<<'(';
		Fract::show();
	}
	double value()
	{
			return i+Fract::value();
	}
};

int main()
{
	Fract f1;
	Dai d2(2,12,16);
	//此处调用的是父类Fract的方法
	f1.show();
	cout<<"f1="<<f1.value()<<endl;
	//此处调用子类Dai 的方法
	d2.show();
	cout<<"d2="<<d2.value()<<endl;
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 02.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
0/1
f1=0
2(3/4
d2=2.75

1.2.子类对象地址赋值给父类指针

#include <iostream>
using namespace std;

class Fract
{
	int n;
	int d;
public:
	Fract():n(0),d(1){}
	Fract(int an,int ad):n(an),d(ad)
	{
			reduce();	
	}
	void reduce()
	{
			if(d<0)//分母小于0
			{
				d=-d;
				n=-n;
			}
			else if(d==0)//分母等于0
			{
				cout<<"d==0!!"<<endl;	
			}
			int absn = (n<0)?-n:n;
			for(int i=d;i>1;i--)
			{
				if(absn%i==0&&d%i==0)	
				{
					n/=i;
					d/=i;	
					break;
				}
			}
	}
	void show()
	{
		cout<<n	<<'/'<<d<<endl;
	}
	double value()
	{
		return (double)n/d;	
	}
};
//子类继承父类
class Dai:public Fract
{
	int i;
public:
	Dai():i(0){} //无参构造函数
	Dai(int ai,int an,int ad) //有参构造函数
	:i(ai),Fract(an,ad){}//初始化列表,父类的参数初始化交给父类去处理	
	void show() //子类和父类中有同名函数,子类中调用父类同名函数调用方法
	{
		cout<<i<<'(';
		Fract::show();
	}
	double value()
	{
			return i+Fract::value();
	}
};

int main()
{
	Fract f1;
	Dai d2(2,12,16);
	Fract* p=NULL;
	
	p = &f1;
	p->show();//此处调用父类Fract的show,无疑问
	cout<<"f1="<<p->value()<<endl;//此处调用父类Fract的value,无疑问
	
	p = &d2;//改变指针指向,父类类型Fract的指针指向子类
	p->show();//此处调用的是父类Fract的show
	cout<<"d2="<<p->value()<<endl;//此处调用的是父类Fract的value
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 03.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
0/1
f1=0
3/4
d2=0.75

自我理解:
(1)指针存储的是一个起始地址,指针可以指针类型(例如:结构体指针)取结构体中的数据。
(2)子类对象在内存分布上,低地址存储的是父类模块,接下来才是存储子类特有的成员。
(3)子类对象地址赋值给父类指针,那么相当于通过父类指针只能获取存放在子类低地址的父类模块。

2.多态实现

如果想通过父类指针,调用子类中的函数,则需要使用多态。
多态真正要做的是:通过指针去访问某个成员函数时,根据对象的真实类型执行相应的类中的成员函数(例如通过父类指针去调用子类的方法)。
C++允许把派生类对象的地址赋值给基类的指针;以此为基础,用基类的指针调用任何方法,C++都能找到相应的派生类的方法。通过这种操作,达到用基类(父类)指针调用子类方法的目的。统一管理、统一操作接口。
多态关键字:virtual。有virtual关键字的函数,称作虚函数。在调用时能够使用多态特性。如果声明和定义分开,只在声明中写virtual。
PS:如果声明和定义分开,常量函数的const在声明和定义中都要写。

2.1.指针实现多态

#include <iostream>
using namespace std;

class Fract
{
	int n;
	int d;
public:
	Fract():n(0),d(1){}
	Fract(int an,int ad):n(an),d(ad)
	{
			reduce();	
	}
	void reduce()
	{
			if(d<0)//分母小于0
			{
				d=-d;
				n=-n;
			}
			else if(d==0)//分母等于0
			{
				cout<<"d==0!!"<<endl;	
			}
			int absn = (n<0)?-n:n;
			for(int i=d;i>1;i--)
			{
				if(absn%i==0&&d%i==0)	
				{
					n/=i;
					d/=i;	
					break;
				}
			}
	}
	//通过virtual实现多态
	virtual void show()
	{
		cout<<n	<<'/'<<d<<endl;
	}
	//通过virtual实现多态
	virtual double value()
	{
		return (double)n/d;	
	}
};
//子类继承父类
class Dai:public Fract
{
	int i;
public:
	Dai():i(0){} 
	Dai(int ai,int an,int ad) 
	:i(ai),Fract(an,ad){}
	void show() 
	{
		cout<<i<<'(';
		Fract::show();
	}
	double value()
	{
			return i+Fract::value();
	}
};

int main()
{
	Fract f1;
	Dai d2(2,12,16);
	Fract* p=NULL;
	
	p = &f1;
	p->show();
	cout<<"f1="<<p->value()<<endl;
	
	p = &d2;
	p->show();//由于多态,此处调用根据d2的真实类型调用子类的show
	cout<<"d2="<<p->value()<<endl;由于多态,此处调用根据d2的真实类型调用子类的value
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 03.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
0/1
f1=0
2(3/4
d2=2.75

2.2.引用实现多态

#include <iostream>
using namespace std;

class Fract
{
	int n;
	int d;
public:
	Fract():n(0),d(1){}
	Fract(int an,int ad):n(an),d(ad)
	{
			reduce();	
	}
	void reduce()
	{
			if(d<0)//分母小于0
			{
				d=-d;
				n=-n;
			}
			else if(d==0)//分母等于0
			{
				cout<<"d==0!!"<<endl;	
			}
			int absn = (n<0)?-n:n;
			for(int i=d;i>1;i--)
			{
				if(absn%i==0&&d%i==0)	
				{
					n/=i;
					d/=i;	
					break;
				}
			}
	}
	//通过virtual实现多态
	virtual void show()
	{
		cout<<n	<<'/'<<d<<endl;
	}
	//通过virtual实现多态
	virtual double value()
	{
		return (double)n/d;	
	}
};
//子类继承父类
class Dai:public Fract
{
	int i;
public:
	Dai():i(0){} 
	Dai(int ai,int an,int ad) 
	:i(ai),Fract(an,ad){}
	void show() 
	{
		cout<<i<<'(';
		Fract::show();
	}
	double value()
	{
			return i+Fract::value();
	}
};

int main()
{
	Fract f1;
	Dai d2(2,12,16);
	Fract* p=NULL;
	
	p = &f1;
	p->show();
	cout<<"f1="<<p->value()<<endl;
	
	p = &d2;
	p->show();
	cout<<"d2="<<p->value()<<endl;

	//引用实现多态
	Fract& f=d2;
	f.show();//由于多态,此处调用根据d2的真实类型调用子类的show
	cout<<"f="<<f.value()<<endl;//由于多态,此处调用根据d2的真实类型调用子类的value
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 03.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
0/1
f1=0
2(3/4
d2=2.75
2(3/4
f=2.75

2.3.多态实现小结

1、有继承关系
2、调用的是虚函数(函数声明中有virtual关键字)
3、访问到的是对象自己(用指针或引用)

3.虚函数表

有虚函数的类,编译器处理时会申请一块内存地址,放所有虚函数的地址,形成虚函数表。每个对象都保存一个虚函数表的地址,都会有一个指向虚函数表的指针。因此都会增加4个字节,不管有多少个虚函数,都只需要一个指针。

3.1.没有虚函数的类大小

#include <iostream>
using namespace std;
#include <string>

class Animal
{
	string name;
public:
	void eat(){
		cout<<"动物吃食物"<<endl;	
	}
	void sleep(){
		cout<<"动物休息"<<endl;
	}
	void shout(){
		cout<<"动物叫"<<endl;
	}
};

int main()
{
	cout<<"sizeof(Animal):"<<sizeof(Animal)<<endl;
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 04.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
sizeof(Animal):32

3.2.有一个虚函数的类大小

#include <iostream>
using namespace std;
#include <string>

class Animal
{
	string name;
public:
	virtual void eat(){
		cout<<"动物吃食物"<<endl;	
	}
	void sleep(){
		cout<<"动物休息"<<endl;
	}
	void shout(){
		cout<<"动物叫"<<endl;
	}
};

int main()
{
	cout<<"sizeof(Animal):"<<sizeof(Animal)<<endl;
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 04.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
sizeof(Animal):40

3.3.有多个虚函数的类大小

#include <iostream>
using namespace std;
#include <string>

class Animal
{
	string name;
public:
	virtual void eat(){
		cout<<"动物吃食物"<<endl;	
	}
	virtual void sleep(){
		cout<<"动物休息"<<endl;
	}
	virtual void shout(){
		cout<<"动物叫"<<endl;
	}
};

int main()
{
	cout<<"sizeof(Animal):"<<sizeof(Animal)<<endl;
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 04.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
sizeof(Animal):40

4.多态举例

4.1.指针实现多态

#include <iostream>
using namespace std;
#include <string>

class Animal
{
	string name;
public:
	virtual void eat(){
		cout<<"动物吃食物"<<endl;	
	}
	virtual void sleep(){
		cout<<"动物休息"<<endl;
	}
	virtual void shout(){
		cout<<"动物叫"<<endl;
	}
};

class Cat:public Animal
{
	public:
		//子类中函数前的virtual可以省略
		//子类中类型需与父类中返回类型一致,参数表一致
		void eat(){
			cout<<"猫吃猫粮"<<endl;
		}	
		void sleep(){
			cout<<"猫在床上睡觉"<<endl;	
		}
		void shout(){
			cout<<"猫喵喵叫"<<endl;	
		}
};

class Dog:public Animal
{
	public:
		//子类中函数前的virtual可以省略
		//子类中类型需与父类中返回类型一致,参数表一致
		void eat(){
			cout<<"狗啃骨头"<<endl;
		}	
		void sleep(){
			cout<<"狗在狗窝睡觉"<<endl;	
		}
		void shout(){
			cout<<"狗汪汪叫"<<endl;	
		}
};

class JiaFei:public Cat
{
	public:
		//子类中函数前的virtual可以省略
		//子类中类型需与父类中返回类型一致,参数表一致
		void eat(){
			cout<<"加菲猫吃意大利面"<<endl;
		}	
		void sleep(){
			cout<<"加菲猫在沙发睡觉"<<endl;	
		}
		void shout(){
			cout<<"加菲猫说下午好"<<endl;	
		}
};

class Player{
public:
	void play(Animal* p){//使用基类指针
		p->eat();	
		p->sleep();	
		p->shout();	
	}
};

int main()
{
	Cat c;
	Dog d;
	JiaFei J;
	Player p1; 
	Player p2; 
	Player p3; 
	
	//实际类型是派生类,传派生类地址
	p1.play(&c);
	p2.play(&d);
	p3.play(&J);
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 05.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
猫吃猫粮
猫在床上睡觉
猫喵喵叫
狗啃骨头
狗在狗窝睡觉
狗汪汪叫
加菲猫吃意大利面
加菲猫在沙发睡觉
加菲猫说下午好

4.2.引用实现多态

#include <iostream>
using namespace std;
#include <string>

class Animal
{
	string name;
public:
	virtual void eat(){
		cout<<"动物吃食物"<<endl;	
	}
	virtual void sleep(){
		cout<<"动物休息"<<endl;
	}
	virtual void shout(){
		cout<<"动物叫"<<endl;
	}
};

class Cat:public Animal
{
	public:
		//子类中函数前的virtual可以省略
		//子类中类型需与父类中返回类型一致,参数表一致
		void eat(){
			cout<<"猫吃猫粮"<<endl;
		}	
		void sleep(){
			cout<<"猫在床上睡觉"<<endl;	
		}
		void shout(){
			cout<<"猫喵喵叫"<<endl;	
		}
};

class Dog:public Animal
{
	public:
		//子类中函数前的virtual可以省略
		//子类中类型需与父类中返回类型一致,参数表一致
		void eat(){
			cout<<"狗啃骨头"<<endl;
		}	
		void sleep(){
			cout<<"狗在狗窝睡觉"<<endl;	
		}
		void shout(){
			cout<<"狗汪汪叫"<<endl;	
		}
};

class JiaFei:public Cat
{
	public:
		//子类中函数前的virtual可以省略
		//子类中类型需与父类中返回类型一致,参数表一致
		void eat(){
			cout<<"加菲猫吃意大利面"<<endl;
		}	
		void sleep(){
			cout<<"加菲猫在沙发睡觉"<<endl;	
		}
		void shout(){
			cout<<"加菲猫说下午好"<<endl;	
		}
};

class Player{
public:
	void play(Animal* p){//使用基类指针
		p->eat();	
		p->sleep();	
		p->shout();	
	}
	void play(Animal& p){//通过引用实现,依然使用基类类型
	p.eat();	
	p.sleep();	
	p.shout();	
}
};

int main()
{
	Cat c;
	Dog d;
	JiaFei J;
	Player p1; 
	Player p2; 
	Player p3; 
	
	//实际类型是派生类,传派生类地址
	p1.play(&c);
	p2.play(&d);
	//p3.play(&J);
	
	//通过引用方式实现,传派生类对象
	p3.play(J);
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 05.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
猫吃猫粮
猫在床上睡觉
猫喵喵叫
狗啃骨头
狗在狗窝睡觉
狗汪汪叫
加菲猫吃意大利面
加菲猫在沙发睡觉
加菲猫说下午好

5.纯虚函数、抽象类(不允许直接创建对象)

上例中基类Animal中的三个函数,始终没有输出过信息,是否可以将这三个函数删除呢?
答案是:不能! 因为后面代码中有使用Animal类型指针,例如调用p->eat(),如果Animal中没有这个函数,则无法调用。

那么这三个函数存在没什么用处,又不能删除,可以将这三个函数只保留声明即可,定义可删除。
函数只声明不定义,如果实际被调用了(例如调用p->eat())则编译报错。可以在声明最后增加“=0”,表示这个函数是个一定不会被执行的函数。这样的函数称作纯虚函数。有纯虚函数的类,叫抽象类
如果直接创建一个抽象类对象,那么就可以通过“对象.成员”的方式调用并执行纯虚函数,而上面讲到纯虚函数是一定不会被执行的函数,所以抽象类不允许直接创建对象。只能用来指向或者引用子类对象。

#include <iostream>
using namespace std;
#include <string>

class Animal
{
	string name;
public:
	virtual void eat()=0;//纯虚函数,一定不会被真正执行的函数
	virtual void sleep()=0;
	virtual void shout()=0;
};

class Cat:public Animal
{
	public:
		//子类中函数前的virtual可以省略
		//子类中类型需与父类中返回类型一致,参数表一致
		void eat(){
			cout<<"猫吃猫粮"<<endl;
		}	
		void sleep(){
			cout<<"猫在床上睡觉"<<endl;	
		}
		void shout(){
			cout<<"猫喵喵叫"<<endl;	
		}
};

class Dog:public Animal
{
	public:
		//子类中函数前的virtual可以省略
		//子类中类型需与父类中返回类型一致,参数表一致
		void eat(){
			cout<<"狗啃骨头"<<endl;
		}	
		void sleep(){
			cout<<"狗在狗窝睡觉"<<endl;	
		}
		void shout(){
			cout<<"狗汪汪叫"<<endl;	
		}
};

class JiaFei:public Cat
{
	public:
		//子类中函数前的virtual可以省略
		//子类中类型需与父类中返回类型一致,参数表一致
		void eat(){
			cout<<"加菲猫吃意大利面"<<endl;
		}	
		void sleep(){
			cout<<"加菲猫在沙发睡觉"<<endl;	
		}
		void shout(){
			cout<<"加菲猫说下午好"<<endl;	
		}
};

class Player{
public:
	void play(Animal* p){//使用基类指针
		p->eat();	
		p->sleep();	
		p->shout();	
	}
	void play(Animal& p){//通过引用实现,依然使用基类类型
	p.eat();	
	p.sleep();	
	p.shout();	
}
};

int main()
{
	Cat c;
	Dog d;
	JiaFei J;
	Player p1; 
	Player p2; 
	Player p3; 
	
	//实际类型是派生类,传派生类地址
	p1.play(&c);
	p2.play(&d);
	//p3.play(&J);
	
	//通过引用方式实现,传派生类对象
	p3.play(J);
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 05.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
猫吃猫粮
猫在床上睡觉
猫喵喵叫
狗啃骨头
狗在狗窝睡觉
狗汪汪叫
加菲猫吃意大利面
加菲猫在沙发睡觉
加菲猫说下午好

6.虚函数注意事项

6.1.构造函数不能是虚函数

虚函数用来实现多态,调同一个接口,构造函数不会主动调用,都是自动调用。

6.2.类中任何一个成员函数是虚函数,则析构函数应为虚函数

父类 *p = new 子类;
delete p;

如果父类中析构函数不是虚函数,则不会调用子类的析构函数。

6.2.1.父类析构不是虚函数
#include <iostream>
using namespace std;

class A{
public:
	A(){cout<<"A()"<<endl;}
	~A(){cout<<"~A()"<<endl;}//不是虚函数
};

class B:public A{
public:
	B(){cout<<"B()"<<endl;}
	~B(){cout<<"~B()"<<endl;}
};
int main()
{
	A* p=new B;
	delete p;
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 06.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
A()
B()
~A()
6.2.2.父类析构是虚函数
#include <iostream>
using namespace std;

class A{
public:
	A(){cout<<"A()"<<endl;}
	virtual ~A(){cout<<"~A()"<<endl;}//是虚函数
};

class B:public A{
public:
	B(){cout<<"B()"<<endl;}
	~B(){cout<<"~B()"<<endl;}
};
int main()
{
	A* p=new B;
	delete p;
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 06.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
A()
B()
~B()
~A()

6.3.一个类注定做父类,尽可能使用虚函数,甚至纯虚函数

如果一个类肯定被用作其他派生类的基类(即注定做父类),尽可能使用虚函数,甚至纯虚函数(用"=0;"代替函数体)。

7.友员

用途:直接访问某个类中私有成员的桥梁。
友员:外面的函数或者另一个类。友员不是成员。友员可以声明/定义在类中的任何地方,声明和定义可以分开,也可以不分开。

7.1.友员函数

#include <iostream>
using namespace std;

class A{
	int data;
public:
	A(int d=0):data(d){}
	void show(){
		cout<<"data="<<data<<endl;			
	}
	friend A add(A a1,A a2);//声明友员,表示对其授权,允许其访问A类中的所有成员。友员不是A的成员函数
};

A add(A a1,A a2){
	int sum = a1.data+a2.data;//访问A中的成员,访问方式:“对象.成员”
	return A(sum);
}

int main()
{
	A a1(40);
	A a2(50);
	add(a1,a2).show();
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 07.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
data=90

7.2.传递对象常用表达方式

凡是向函数中传对象时,几乎都是用引用,只要不需要改变这个对象,几乎都会加const。

#include <iostream>
using namespace std;

class A{
	int data;
public:
	A(int d=0):data(d){}
	void show(){
		cout<<"data="<<data<<endl;			
	}
	friend A add(const A& a1,const A& a2);//声明友员,表示对其授权,允许其访问A类中的所有成员。友员不是A的成员函数
};

A add(const A& a1,const A& a2){ //使用引用,由于不改变这个对象,再加const
	int sum = a1.data+a2.data;//访问A中的成员,访问方式:“对象.成员”
	return A(sum);
}

int main()
{
	A a1(40);
	A a2(50);
	add(a1,a2).show();
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 07.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
data=90

7.3.友员类

#include <iostream>
using namespace std;

class A{
	int data;
public:
	A(int d=0):data(d){}
	void show(){
		cout<<"data="<<data<<endl;			
	}
	friend class B;//声明友员,表示对其授权,允许其访问A类中的所有成员。友员不是A的成员函数
};

class B{
public:
	void twice(A& a){ //类的传递使用引用实现,由于要改变这个对象,所以不加const
		a.data *= 2;
	}
};

int main()
{
	A oa(50);
	B ob;//定义友员类对象
	ob.twice(oa);//使用友员对象将对象oa中data数值加倍
	oa.show();
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 08.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
data=100

8.静态成员

凡是所有对象共用一份的数据,都要声明为静态数据成员;所有对象一致的方法都要声明成静态方法。例如学生是对象,教室是共用的,更换老师是共同的行为。所有的同一类对象都使用一份数据。
静态数据成员又称为类变量;它属于这个类,被该类的全体对象共享;
静态函数成员又称为类方法/类行为;
静态数据成员像全局变量一样在所有函数之外初始化。(java中没有全局变量,拿静态数据成员当全局变量使用)

8.1.静态数据成员(类成员)

#include <iostream>
using namespace std;

class Sd0705{
public:
	string name;
	static string teacher;//静态数据成员声明
	static int room;//静态数据成员声明
	
	Sd0705(const string& n):name(n){}//构造函数
	void show(){
		cout<<"我是"<<name<<",在"<<room<<"教室听"<<teacher<<"讲课"<<endl;
	}
};

string Sd0705::teacher="陈宗权";//静态数据成员初始化
int Sd0705::room=712;//静态数据成员初始化

int main()
{
	Sd0705 s1("张三");
	Sd0705 s2("李四");
	Sd0705 s3("沙雕");
	
	s1.show();
	s2.show();
	s3.show();
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 09.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
我是张三,在712教室听陈宗权讲课
我是李四,在712教室听陈宗权讲课
我是沙雕,在712教室听陈宗权讲课

8.2.静态函数成员(类方法)

公共的静态函数成员就是一个全局函数;
对公共的静态函数可以直接调用,不需要通过任何对象;
静态成员函数中不得使用非静态数据成员;

#include <iostream>
using namespace std;

class Sd0705{
public:
	string name;
	static string teacher;
	static int room;
	
	Sd0705(const string& n):name(n){}//构造函数
	void show(){
		cout<<"我是"<<name<<",在"<<room<<"教室听"<<teacher<<"讲课"<<endl;
	}
	static void  chgTeacher(const string& t){//静态函数成员,更换老师
		teacher =t;
	}
};

string Sd0705::teacher="陈宗权";//静态数据成员初始化
int Sd0705::room=712;//静态数据成员初始化

int main()
{
	Sd0705 s1("张三");
	Sd0705 s2("李四");
	Sd0705 s3("沙雕");
	
	s1.show();
	s2.show();
	s3.show();
	
	Sd0705::chgTeacher("谢老师");//调用静态函数成员,调用方法“类名::静态函数成员”,不提倡使用”对象.成员“
	s1.show();
	s2.show();
	s3.show();
}

执行结果:

root@host:/home/LinuxShare/004.c++/day10# g++ 10.cpp
root@host:/home/LinuxShare/004.c++/day10# ./a.out
我是张三,在712教室听陈宗权讲课
我是李四,在712教室听陈宗权讲课
我是沙雕,在712教室听陈宗权讲课
我是张三,在712教室听谢老师讲课
我是李四,在712教室听谢老师讲课
我是沙雕,在712教室听谢老师讲课
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值