包含对象成员的类
valarray
int gpa[5]={3,1,1,3,2,3};
valarray<int> a1;//空数组
valarray<int> a2(8);//指定长度
valarray<int> a2(10,8);//指定长度,指定数组
valarray<int> a2(apg,4);//常规数组的指定元素
初始化被包含的对象
Son::Son ():Father(){}//初始化派生类中的基类
Son::Son ():String(”丁文“){}初始化派生类中的成员对象string
因为初始化的是派生类的成员对象,所以不用类名来初始化,而是用对象名初始化。这样将会调用成员对象的构造函数。
注意
初始化的顺序是定义时的顺序,成员列表的顺序,但是如果代码使用一个成员的值作为另一个成员的初始化表达式的一部分,初始化顺序就非常重要
使用被包含对象的结构
我们可以使用被包含对象的共有接口
私有继承
has-a关系的实现是通过私有继承的
基类的共有成员和保护成员都将成为派生类的私有成员
访问基类的方法
1由于私有继承方法继承过来的方法是私有的,如果你想让他变成共有,就写一个共有函数里面再调用私有函数
2私有继承可以使用类名和作用域解释符运算符来调用基类方法
访问基类对象
使用类名加上作用域解释符就可以访问基类可以使用基类的方法,那么私有对象本省,答案是对this指针强制转换为基类型
访问基类的友元函数
前面说了共有继承,说可以在不显示转换的情况下基类的引用和指针类型,可以指向派生类。而在私有继承中,如果派生类型对象 想使用基类的友元函数,必须把自己强制转换为基类型对象,
保护继承
使用using中定义访问权限
class Son:public Father{
public :
using Father:f;//只需要写函数名就可以了
}
Son s;
s.f();//就像使用够用函数一样
多重继承
class A{
}
class B:public A{
}
class C:public A{
}
class D:public B,public C{
}
想上面这样的继承关系会出现一个很好玩的情况,D中有两个A对象(一个B中的A,一个C中的A),那么怎么办呢?
1使用强制转换符
D d;
A a=d;//派生类隐式转为基类
A a1=(C)a;//同理
A a2=(D)a;//同理
虚基类
class A{
}
class B:virtual public A{
}
class C: public virtual A{//先后顺序无所谓
}
class D:public B,public C{
}
如果像上上面定义的话,D中只能有一个A的副本,知道定义之后我们来解决下面三个问题
1为什么要用“虚”
2为什么不抛弃多重继承
3麻烦吗
解答
1写c++规则的人很烂(起始是让你们学习容易记),所以用已有的关键字
2因为有时候只有多继承能解决问题
3这个就单独在下面说了
新的构造函数
class A{
int a;
public :
A(int=0):a(n){};
}
class B:virtual public A{
int b;
public :
B(int m=0,int n=0):A(m),b(n){};
}
class C: public virtual A{
int c;public :
B(int m=0,int n=0):A(m),c(n){};
}
class D:public B,public C{
int d;public :
B(int m=0,int n=0,int q=0):B(m,n),C(m,n),c(q){};
}
上面的继承树种D将间接的A进行初始化,一条路是通过B,另一条是通过C,所以这样会出现冲突,但是编译器还是会通过的 为什么呢?因为系统会在初始化B和C之前先调用A的默认构造函数初始化A ,但是不想调用默认的我们可以通过显示调用构造函数的方法实现下。
class D:public B,public C{
int d;public :
B(int m=0,int n=0,int q=0):A(m),B(m,n),C(m,n),c(q){};
}
上面的只能在虚基类中是合法的,在正常的类中成员初始化列表不能初始化基类的基类的成员。
函数使用问题
class A{
int a;
public :
A(int=0):a(n){};
}
class B:virtual public A{
int b;
public :
B(int m=0,int n=0):A(m),b(n){};
f();
}
class C: public virtual A{
int c;public :
B(int m=0,int n=0):A(m),c(n){};
f();
}
class D:public B,public C{
int d;public :
B(int m=0,int n=0,int q=0):B(m,n),C(m,n),c(q){};//调用默认的构造函数A();
}
上面D如果调用f()会出现二义性,因为编译器不知道调用的是B还是C中的f(),解决办法是使用作用域解释符。像这样二义性的问题还有很多,不一一例举了。注意一点就是,在调用函数的时候,调用的都是他上级基类的函数,注意不要让同一层级的基类函数重复,如果重复就使用作用域解释符就没错了
混合使用虚基类和非虚基类
B作为C,D的虚基类,同时也是X,Y的基类,M继承C,D,X,Y,这样的话M中就有三个B类,一个是C,D的共享的,两个个是X,Y的。
类模板
template <class Type>//class可以用typename代替
//定义类
class A{
private :
int a;
public :
A();
void f(const Type &);
void f2(Type & )
};
//类的构造函数
template <class Tyoe >
A<Type>::A(){
}
//类的普通函数
template<class Type>
void A<type>::f(const Type& a){
}
template<class>A<type>::f2( Type& a){
}
上面每一个函数都已相同的函数头声明template<class Type>
使用模板类
数组模板示例和非类型参数
Array<double 12>a1;
Array<double 13>a2;
Array<int>a4(12);
Array<int>a4(13);
模板多功能性
template<typename T>
class Array{
private :
T a;
}
template<type Type>
class B:public A<type>{}
template<typename T>
class C
{
A<T> a;
}
A< <B<int> > a;
递归使用模板
A<A<int,5> ,5> a;
int a[10][5];
class A{
T1 a;
t2 B;
}
template<class T1,class T2=int>class A{...};
模板的具体化
A<int,100> a;//没有隐式实例化,因为还没有需要对象,所以只是生成类具体类的定义
pt=new A<int ,30>;//进行类隐式初始化,生成了对象
template class A<string ,100>;
template<> class clssname<specialized_tyoe-name>{};
template<>class A(const char*){
.....
}
4部分具体化
如果有多个模板可以选择,编译器将使用具体化成都最高的模板A
template<class T1>class A{};//T2为int
template<class T1>class A<T1,int>{};//T2为int
<double,double>p1;//使用第一个模板
A<double,int>p1;//使用第二个模板
A<int,int>p2;//使用第二个模板
teemplate<class T1,classT2,class T3>class A{};
template<class T1,class T2>class A<T1,T2,T3>{};
template<class T1>class A(T1,T1*,T1*){};
A<int,short,char*>t1;//1
A<int ,short>t2;//2
A<char,char*,char*>t3;//3
成员模板
将模板用作参数,模板本身就是模板的参数
template<template <typename T>class A>;
模板类和友元
class A{
public :
friend void f(A<T> &);
}
void f(A<short>&){};//定义的模板类的友元
void f(A<int> &){};
template<typename T> void f2<>();
template<typename T>//第二部定义模板类
class A{
public :
friend void f<>(A<T> &);//显示具体化
friend void f2<T>();//f2没有参数所以,所以必须使用指定的参数来知名显示具体化
}
A<int> a;//第三步定义变量
template <class T>
class A{
template <typename C,typename D>friend void f(C&,D&);
}
当我们调用函数时会进行实例化 根据参数生成相应的函数 如果调用函数时传递的是A<int & >就会和下面匹配
void f<A<int &>,A<int &>>(A<int &>,A<int &>){};
c++11模板别名