一:继承与派生类
(一)继承
1.继承是一个进程,通过继承,一个对象可以获得另一个对象的属性,也就是说,一个对象可以继承属性的集合,并可向其中加入属于自己的一些特征。
2.继承允许一个对象支持多层分类的概念。
(二)派生类
1.类继承可以从一个类即基类中继承该基类的成员,并增加新的成员;
例:
class A//定义基类A
{int i;
public:
void f1(int a);
int f2();
};
class B:public A//根据基类A定义派生类B
{int j;
public:
void g1(int a);
int g2();
};
注:基类A的所有公有成员也是派生类的公有成员,但基类A的所有私有成员仍属于A类,不被派生类继承;
2.一个类可以有直接基类和间接基类;
二:单继承
从一个基类派生的继承称为单继承,即派生类只有一个直接基类;
单继承声明语句的常用形式为:
class 派生类名:访问控制关键字 基类名
{数据成员和成员函数声明
};
三:访问控制关键字
若访问控制关键字为public,则称派生类从基类公有继承,也称公有派生;若访问控制关键字为private,则称派生类从基类私有继承,也称私有派生;
1.公有继承
公有继承不改变访问级别,派生类的对象可以直接使用基类所有的公有方法,除非这些方法在派生类中又重新定义;注意派生类的成员不能直接访问基类中的私有属性,基类的保护成员在派生类中仍是保护成员;
2.私有继承
a.在私有继承情况下,基类的所有成员都变成派生类的私有成员,注意积累的私有成员被继承后,派生类仍不能访问它,这说明不能通过派生类的对象访问基类的任何成员;
b.私有继承表明派生类对象不能直接访问基类的公有成员,派生类的函数可以访问基类的公有成员;
3.保护成员
有时希望派生类能够访问基类的成员,但又不想把基类的这些成员声明为公有,最好的方法是在基类的定义中使用保护访问控制关键字protected;
(1)在定义类时,使用关键字protected声明类的成员函数为保护成员:
class A
{protected:
int a;
};
注:a是保护的成员,保护成员具有私有成员和公有成员的双重角色。
(2)在基类保护部分定义的任何成员在派生类中都可以看做是公有成员,而在程序的其他部分是私有的,即基类的保护成员在派生类中是公有成员,在派生类之外是私有成员;
四:多继承与继承链
1.多继承
(1)从多个基类派生的继承称为多继承或多重继承,也就是说一个派生类有多个直接基类。
(2)多继承声明语句的形式为:
class 派生类名:访问控制关键字 基类名1,访问控制关键字 基类名2,…
{
数据成员和成员函数声明
};
2.继承链
(1)一个派生类继承多个基类的方法有两种:
第一种方法:派生类可以作为基类供别的类继承,产生多层次的继承关系,在此情况下,原始的基类可以称为第二个派生类的间接基类;
第二种方法:派生类可以直接继承多个基类,此时,多个基类联合创建一个派生类;
(2)类的层次结构也叫作继承链,注意调用析构函数的顺序恰好与构造函数调用的顺序相反;
例:
#include <iostream.h>
using namespace std;
/* run this program using the console pauser or add your own getch, system(“pause”) or input loop /
class B1
{private:
int a;
public:
B1(int x){a=x;}
int geta()
{
return a;
}
};
class D1:public B1
{private:
int b;
public:
D1(int x,int y):B1(y)//将y传递给B1
{b=x;}
int getb()
{
return b;
}
};
class D2:public D1
{private:
int c;
public:
D2(int x,int y,int z):D1(y,z)//将参数y,z传递给D1
{c=x;}
void show()
{
cout<<geta()<<" “<<getb()<<” “;
cout<<c<<”\n";
}
};
int main(int argc, char* argv)
{
D2 ob(1,2,3);
ob.show() ;
cout<<ob.geta()<<ob.getb() <<"\n";
return 0;
}
3 2 1
32
Process exited after 0.4565 seconds with return value 0
请按任意键继续. . .
注:B1是D1的间接基类,D2可以访问D1和B1的公有成员,故geta()是D1的公有成员同时也是D2的公有成员;注意在继承链上的每个类必须传递基类所需的所有变量,否则将导致错误;
五:友元类和友元函数
友元是C++提供的一种破坏数据封装和数据隐藏的机制。如果讲一个模块申明为另一个模块的友元,则模块能够引用另一个模块原本隐藏的信息;友元可以访问类的所有成员(包括私有成员在内);
C++有两种模块:即函数(不是成员函数)和类;
(一).友元类
1.friend修饰符(关键字)可以修饰一个函数或类,被friend修饰的类称为友元类;
例:
class B;
class A
{friend class B;/ *声明类B是类A的友元类,类B可以直接使用类A中的成员,也意味着类B的所有成员函数将成为类A的友元函数 */
public:
void display() {cout<<x<<endl;}
private:
int x;
};
class B
{
public:
void set(int i);
void display() ;
private:
A a;
};
void B::set(int i)
{x=i;}
void B::display()
{display();}
注:
a.被声明为友元类的类必须提前声明;
b.友元类的声明既可以位于类的公有部分,也可以位于类的私有部分;
c.友元关系不能继承;
(二)友元函数
1.类的私有成员只能通过类的成员函数进行访问。如果希望使用非成员函数访问类的私有变量,可以通过有元函数实现,友元函数不是类的成员函数,但他可以访问类的私有成员;
2.如果一个函数是一个类的友元函数,必须在类中进行申明,声明形式为:
friend 类名 函数名(参数表);
3.,友元函数不是类的成员函数,友元函数的定义可以在类内或类外定义;
4.friend int isfactor(A,ob);其中A是类名称,向isfactor()函数传递一个A类的对象ob,这也是isfactor()函数能够访问私有函数的原因,虽然一个友元函数可以访问类的私有成员,但在访问过程中必须通过该类的对象进行访问,,即友元函数访问变量时必须与在友元函数中定义或传递给友元函数的对象联系在一起;
5.友元函数可以作为多个类的友元,例如当两个不同的类要进行比较时,经常使用一个友元函数;
例:共用一个友元函数:
#include <iostream.h>
using namespace std;
/* run this program using the console pauser or add your own getch, system(“pause”) or input loop /
class truck;
class car
{
int passengers;
int speed;
public:
car(int p,int s){passengers=p;speed=s;}
friend int sp(car c,truck r);
};
class truck
{
int weight;
int speed;
public:
truck(int w,int s){weight=w;speed=s;}
friend int sp(car c,truck t);
};
int sp(car c,truck t)
{
return c.speed-t.speed;
}
int main(int argc, char* argv)
{
int t;
car c1(4,50),c2(5,70);
truck t1(100,50),t2(200,60);
cout<<“compare c1 and t1:\n”;
t=sp(c1,t1);
if(t<0) cout<<“truck is faster.\n”;
else if(t0) cout<<“truck and car speed is the same.\n”;
else cout<<“car is faster.\n”;
t=sp(c2,t2);
if(t<0) cout<<“truck is faster.\n”;
else if(t0) cout<<“truck and car speed is the same.\n”;
else cout<<“car is faster.\n”;
return 0;
}
compare c1 and t1:
truck and car speed is the same.
car is faster.
Process exited after 0.116 seconds with return value 0
请按任意键继续. . .
六:模板
模板也叫参数化的类型,利用模板可以构造出一系列的相关函数或类。
模板有函数模板和类模板两种类型;
(一)函数模板
1.函数模板的声明语法为:
template<模板参数表>
类型名 函数名(参数表)
{
函数体
}
a.其中template为模板声明关键字。
b.在早期C++版本中,模板参数表的参数类型为关键字class,多个参数之间通过逗号隔开;在C++的新版本中,使用关键字typename作为类型,作用与class一致,在模块函数声明中,一般使用T作为模板参数标识符,T代表任意类型;
c.例如下列写法:
template< class T>
template< typename T>
template<class T1,class T2>
template<typename T1,typename T2>
2.一旦声明了一个参数化的类型名,就可以在函数声明中引用该类型名。在函数模板的声明部分,参数表内的参数类型和函数的返回类型应为已声明的参数化类型名;
例:
template< class T>
T f1(T a)
{return a<0?-a:a;}
#include<iostream.h>
void main()
{
int x=2;
float y=0.4;
cout<<f1(x)<<endl;
cout<<f1(y)<<endl;
}
程序输出结果为:
2
0.4
3.在组织程序时,通常将函数模板的声明及其实现放在一个头文件内,以便C++编译程序时能在试用前知道函数模板时存在的;
例:
#define F1_H
#ifndef F1_H //if not define 防止多重定义
T f1(T a)
{return a<0?-a:a;}
#endif
主程序应为以下形式:
#include<iostream.h>
#include"f1.h"
void main()
{
int x=2;
float y=0.4;
cout<<f1(x)<<endl;
cout<<f1(y)<<endl;
}
4.在函数模板中选择对应的函数,如果找到了就调用它;若找不到对应的函数,则先转化参数类型重新寻找;若依旧找不到则为一个失败的调用;
(二)类模板
1.类模板的声明语法为:
template<模板参数表>
类声明
2.模板参数表内的参数类型为关键字class或typename,多个参数之间用逗号隔开;
3.例声明类模板:
template< T >
class tany
{
private:
T x,y;
public:
tany(T a,T b) {x=a;y=b;}
T getx() {return x;}
T gety() {return y;}
};
4.tany< int> iob(22,33);
表达式< int>告诉编译程序从模板产生一个类,并用int替换所有的T;新类的名字变成tany< int>,对象名为iob;