1. 结构体也可以继承,可以有虚函数、构造、析构,与class唯一区别是默认public
定义结构体变量时struct关键字可省略 (类也一样)
2. 编译器为空类产生4个成员函数 默认构造函数,析构函数,拷贝构造函数,赋值函数
注意拷贝构造是构造 String c = a;
c = a;是赋值
即使只定义了有参构造,编译器也不会再产生默认的无参构造
赋值函数
String & String::operate = (const String &other)
//返回String& 类型
//参数要const 否则在右操作数 是const情况下就不能用了
{
if(this == &other) //检查自赋值 否则自赋值会出错
return *this;
delete [] m_data; //注意先释放
int len = strlen(other.m_data);
m_data = new char[len+1];
strcpy(m_data, other.m_data); //strcpy会加上0
return *this;//返回值是自己
}
(运算符重载写法与函数一样,只是函数名为operate =)
3. 对象初始化
三种初始化方式
A a(1); A a = A(1); A a = 1;必须只有一个参数
注意 A a(); 是声明了一个函数 返回A类型 无参构造就不要()
A a = 1;属于隐式调用构造函数,构造函数前加explicit可阻止隐式调用
拷贝构造
A(const A& a){} 可不要const 但一定要& (没有&,则本身也需要拷贝)
要禁止拷贝可以显式定义private的拷贝构造
构造函数的初始化列表 A():x(1),y(2){};
作用 需要初始化的数据成员是对象
需要初始化const修饰的类成员
需要初始化引用成员数据
这三种无法在构造函数里初始化
对象如果有无参构造,则可以不用在此初始化
继承可用此方法初始化父类的private成员
只有static const的整形数据成员 可以在类定义中初始化
初始化是按照变量声明顺序,先声明的变量在后面就不会被初始化
默认参数在函数的声明和定义中只能出现一次
类成员函数的const限定符必须在声明和定义时同时指定
4. 继承
三种继承方式,公保成员对子类都可见,成为子类的公保、保、私成员
保护成员对类的对象不可见 目的是为了继承可见
默认是私有继承
各个类的同名变量没有覆盖,各个类的函数所用的变量都是自己的,初始化时各自初始化自己的
子类要替父类初始化可通过初始化列表:A(1)
若子类对象调了父类的函数,父类的函数再调用函数时也是调父类的,当被调函数为虚时才应用动态关联尝试调子类
若指明调用 c.A::f() 即使虚函数也直接调A
用父类指针给子类指针赋值,调的仍是父类函数
多态本质就是将子类类型的指针(引用)赋值给父类类型的指针
用子类对象给父类对象赋值就不会有多态效果,子类新增成员会丢失
父类函数虚拟,则子类自动成为虚拟,可以不用指明
子类虚函数的声明必须与父类的声明一致,返回值可以是父类返回值的子类(gcc中),参数不可以
将析构函数写为virtual 防止通过父类指针释放时 没有调用子类析构函数
但构造函数不能是虚拟的
析构函数可以是inline的
纯虚函数 virtual void f()=0;
含有纯虚函数的类称为抽象类,不能实例化,子类若未实现纯虚函数也不能实例化
阻止类的实例化 还可以用private构造函数
多继承中,如果几个父类又共同继承自一个类(菱形继承),应使用虚继承
class A;
class B:public virtual A;
class C:public virtual A;
class D:public B,public C;
5. 模板
template<class Type, int size> 在模板参数表中typename与class等价,size在模板实例化时替换为一个常量
模板在继承时也要带上Type :public A<Type>
成员函数定义
Template<class T>
Void A<T>::f(){}
类模板的成员函数定义也要写在头文件中,因为模板函数在调用时才编译
(export关键字编译器不支持,或者include cpp文件)
模板类继承 class Extend_queue:public Queue<Entry>
6. STL
vector,list(双向链表),deque,stack,
queue,priority_queue(后三种是容器适配器,没有迭代器)
map(关联容器,红黑树实现),set(集合,不重复,红黑树实现),multiset(允许重复)
algorithm头文件 for_each为每个元素调用指定函数 stable_sort稳定排序
vector
vector<int> vec;
vec.push_back(12);
vector<int>::iterator p;
p = vec.begin();
*p = 68;
cout<<vec[0]<<endl;
删除vector时会将存储的对象也析构 ,所以如果对象没有拷贝构造,可能会两次释放同一内存
Push_back对象的时候会调用两次拷贝构造,一次析构