概念:
有时候当我们需要好几种类的时候,有些类里面的成员可能会存在重复的情况,那就在想有没有一种办法可以,让这些类既有大家都共同拥有的,也要有自己独有的呢? -- 继承
继承后父类的数据A会变成 子类的一部分
class S { public: int a; }; class W :public S //public为继承的方式 { public: int b; };
访问方式:
不可见意思就是子类的 类外 和 类里都不能访问;protected / private:子类的 类里可以访问,类外不可以。
如果基类成员需要在派生类中被访问,但是又不想被类外访问就定义为protect,这也看出保护成员限定符是因继承才出现的。
class 的默认继承方式是private ;struct 是 public
赋值转换
派生类对象可以赋值给 基类的对象 / 基类的指针 / 基类的引用。把派生类中父类的那部分数据切来赋值过去 (只有公有继承的父子类,才可以实现)
但是父类的对象不能赋值给子类 !
重定义:
如果子类和父类有同名的成员,那么访问子类里的这些数据,会优先访问子类的,屏蔽父类的,这个叫做隐藏,也叫做重定义。(但不建议定义的时候有重名的成员)
class S { public: void f() { cout << "Hello !" << endl; } }; class M :public S { public: void f(int) { cout << "Hello !" << endl; } }; int main() { S a; M b; a.f(); b.f(); b.f(8); return 0; }
可以看到这里的f函数也是 隐藏(重定义) 。
不是重载哦 重载需要两个这里的两个函数在同一作用域里面。
这个代码是无法正常允许的,会在编译的时候出错。
友元:
友元没有传递的这个说法,一个函数/类是父类的友元,但不是它不会是派生类的友元
友元关系不会被继承!!!!
派生类的friend函数可以访问派生类本身的一切变量,包括从父类继承下来的protected域中的变量。但是对父类来说,他并不是friend的。
class B; class A { friend B; private: int a; }; class B : public A { public: void fun() { cout << a; } int b; };
这段代码中 数据a 是被private限定的,无论什么继承都是private,不能访问的,但是如果我让子类B成为了父类A的友元,就可以在B类里面访问了,当然类外依旧是不可以的!!!
静态成员:
在继承中,静态成员,父类和子类都可以访问,属于是共用的
class A { public: static void dunc() { cout << "Hello" << endl; } int a; }; class B : public A { public: int b; }; int main() { B::dunc(); return 0; }
默认函数:
子类会优先调用父类的构造函数初始化那些继承自父类的成员,然后再初始化自己的。
class S { public: S(int num ) { x = num; } int x; }; class M :public S { public: M(int m = 11, int n = 22) : y(n), x(m) { } int y; }; int main() { M b; return 0; }
这个代码是会报错的哦。S类没有构造函数,而子类会优先调用父类的构造,就报错了,还有一个错误:
这个可以这样解决(赋值 拷贝构造函数也是这样):
class S { public: S(int num) { x = num; } int x; }; class M :public S { public: M(int m = 11, int n = 22) : y(n), S(m) { } int y; }; int main() { M b; return 0; }
当然这样 x 就变成11了,这里依然也是先调用S的构造函数,初始化列表初始化顺序是看变量的声明顺序的,默认继承自父类的成员是最前的
class S { public: S(int num) { x = num; } S(const S& data) { x = data.x; } S& operator=(const S& data) { if (this != &data) { x = data.x; } } int x; }; class M :public S { public: M(int m = 11, int n = 22) : y(n), S(m) { } M(const M& data) :S(data.x), y(data.y) { } M& operator=(const M& data) { if (this != &data) { S::operator=(data.x); y = data.y; } } int y; };
拷贝构造函数需要声明是父类的,不然会和子类的拷贝构造函数构成 隐藏
子类的析构函数不需要显示的调用父类的析构函数:
① 显示调用如果不声明会构成 隐藏 :因为多态的需要,析构函数名会被统一为destructor()
② 即使你声明了是调用父类的析构,因为析构顺序就是先子后父,子类析构完会自动调用父类的