类与类之间的关系
组合类:
一个类是另一个类的一部分
例:head --- {eye,nose}
代理类:
一个类中的方法是另一个类方法的子集
例:list --- > stack
继承:
一个类是另一个类的一种
例:动物 ----> 猫 狗..
三种访问属性:
1:可访问 0:不可访问
外界 子类 自身
public: 1 1 1
protected: 0 1 1
private: 0 0 1
在子类的类定义后面加上 : 父类名字
public:
protect:
private:
默认继承权限是private
class A { public: int a; void fun1() { cout << "public void fun1() " << endl; } protected: int b; void fun2() { cout << "protected void fun2() " << endl; } private: int c; void fun3() { cout << "private void fun3() " << endl; } };
继承权限限制的是子类继承父类之后,父类的成员在子类中的最低访问权限
如果采用private的方式继承,则会将父类中的public和protected放在子类中的private
子类中可以访问,外界不可访问
采用public继承时,private继承不下来
class B :public A { public: int a; void fun1() { cout << "public void fun1() " << endl; } int a1; protected: int b; void fun2() { cout << "protected void fun2() " << endl; } void fun_tmp() { cout << a << endl;//A::public cout << b << endl;//A::protected //cout << c << endl;//A::private } int b1; private: /* */ int c1; };
采用protected继承时,只能继承protected
class B :protected A { public: int a1; protected: int b; void fun2() { cout << "protected void fun2() " << endl; } void fun_tmp() { cout << a << endl;//A::public cout << b << endl;//A::protected //cout << c << endl;//A::private } int b1; private: /* */ int c1; };
采用private时,一个都继承不了(相当于私有继承)
class B :private A { public: int a1; protected: int b1; private: /* */ int c1; };
继承方式一般采用public
函数之间的关系
重载
继承中成员方法的关系
隐藏
子类中的成员方法会隐藏父类中同名的成员方法 ------ 同名隐藏
访问被隐藏的父类成员方法使用父类作用域即可
覆盖
组合类:
class A{}
class B
{
B():A(){}
A a;
}
B b;
先构造成员对象 ---》 再构造自身对象
先析构自身对象----》再析构成员对象
继承类:
先构造父类 ---- 》再构造子类 ------子类的构造函数一定在初始化列表进行了父类的构造
先析构子类 -----》再析构父类
如果类中存在必须再自身构造之前需要完成的事情,就一定要在初始化列表中完成
#include<string> class Animal { public: Animal(const string& name) :_name(name)//初始化列表 { cout << "Animal(const string& name)" << endl; } void eat() { cout << _name << " eat eat eat……" << endl; } void run() { cout << _name << " walk walk walk……" << endl; } ~Animal() { cout << "~Animal()" << endl; } protected: const string _name; }; class Cat : public Animal { public: Cat(const string& name) :Animal(name) { cout << "Cat(const string& name)" << endl; } void sleep() { cout << _name << " sleep sleep sleep ……" << endl; } void eat(int a)//同名隐藏 { cout << _name << " eat fish……" << endl; } ~Cat() { cout << "~Cat()" << endl; } /* void eat() { cout << _name << " eat eat eat……" << endl; } void run() { cout << _name << " walk walk walk……" << endl; } */ }; int main() { Cat cat("cat"); //cat.eat(); //cat.Animal::eat(); //Animal a("ss"); return 0; }
覆盖
virtual修饰的成员方法就是虚函数
.text
.data .bss
.rodata---只读数据段 read only data 虚函数表存放在rodata段
对象调用
直接取text段调用对应的函数指令
会先去虚函数表中找到对应的虚函数指针
再去text段中虚函数指针对应的位置调用找到的函数
virtual存在继承性
比如父类中为 virtual void fun1() 子类中为 void fun1()
则子类中的fun1同样会被处理为virtual
虚函数在继承中存在覆盖的可能性
1.父类中的成员方法必须是虚函数
2.子类中成员方法和父类中成员方法相同---(函数名相同,参数列表相同,返回值相同)
如果多个父类中存在虚表,继承之后子类中就会有多个虚表
class Base2 { public: int b; virtual void fun5() { cout << "Base2::fun5()" << endl; } virtual void fun6() { cout << "Base2::fun6()" << endl; } virtual void fun() { cout << "Base2::fun()" << endl; } }; class Base { public: int a; virtual void fun1() { cout << "Base::fun1()" << endl; } virtual void fun2() { cout << "Base::fun2()" << endl; } void fun3() { cout << "Base::fun3()" << endl; } virtual void fun() { cout << "Base::fun()" << endl; } }; class Drive : public Base2, public Base { public: void fun1() { cout << "Drive::fun1()" << endl; } void fun5() { cout << "Drive::fun5()" << endl; } virtual void fun4() { cout << "Drive::fun4()" << endl; } void fun() { cout << "Drive::fun()" << endl; } int c; }; typedef void(*TYPE_FUN)(); void printf_vftable(TYPE_FUN* table) { for (int i = 0; table[i] != NULL; i++) { cout << "[" << i << "]" << table[i] << endl; table[i](); } } int main() { #if 0 cout << sizeof(Base) << endl; Base tmp1; /* Drive tmp2; tmp2.fun1(); tmp2.Base::fun1(); */ //父类指针指向子类对象 Drive* p = new Drive(); p->fun1(); p->Base::fun1(); Drive tmp2; #endif //Base tmp1; //Base* tmp = &tmp1; //printf_vftable(((TYPE_FUN**)tmp)[0]); Drive tmp2; Base* tmpp = &tmp2; //printf_vftable(((TYPE_FUN**)tmpp)[0]); tmpp->fun(); return 0; }
函数之间的关系重载
继承中成员方法的关系隐藏子类中的成员方法会隐藏父类中同名的成员方法 ------ 同名隐藏访问被隐藏的父类成员方法使用父类作用域即可
覆盖