本节知识点:
1.继承的概念:
a.面向对象中的继承指类之间的父子关系,
子类拥有父类的所有成员变量和成员函数,
子类就是一种特殊的父类,
子类对象可以当作父类对象使用,
子类可以拥有父类没有的方法和属性
2.类的protected属性成员:
a.
protected成员可以在本类和子类中被访问,但不能在外界被访问。protected成员的访问权限介于public和private之间。
3.c++中的访问级别与继承:
a.
继承时的访问级别设定会影响到成员的访问级别,c++中class的默认继承为private继承
b.
private继承的子类拥有父类的所有成员,private继承使得父类的所有成员在子类中变成private成员
c.public继承,父类成员在子类中保持原有访问权限。private继承,父类成员在子类中变成为private成员。protected继承,父类中访问权限比protected高的,保持原有权限,其余的访问权限变成protected。
d.
最长用的继承方式为,public继承。类的成员常用protected属性和public属性。
4.类成员访问级别设置的原则:
a.需要被外界访问的成员直接设置为public
b.只能在当前类中访问的成员设置为private
c.只能在当前类和子类中访问的成员设置为protected
d.
private成员在子类中依然存在,但是却无法访问到
示例代码:
#include <iostream>
using namespace std;
class test
{
private:
int a;
protected:
int b;
public:
int c;
test()
{
a = 1;
b = 2;
c = 3;
//cout << "test()" <<endl;
}
void print()
{
cout << a << " " << b << " " << c <<endl;
}
};
class t1 : public test
{
};
class t2 : protected test
{
public:
void fun()
{
t2 q;
q.b = 10;
q.print();
}
};
int main()
{
t1 t;
t.c = 12;
t.print();
t2 p;
p.fun();
//p.b = 10; //因为b是protected属性的 只能在本类和子类中使用
//p.print(); //因为p是protected继承方式 所有print为protected属性 不能在外界使用
return 0;
}
5.子类与父类的赋值兼容性原则:
a.
子类对象可以当作父类使用,子类就是特殊的父类
b.子类对象可以直接赋值给父类对象
c.子类对象可以直接初始化父类对象
d.父类指针可以直接指向子类对象
e.父类引用可以直接引用子类对象
示例代码:
#include <iostream>
using namespace std;
class test
{
protected:
int a;
public:
void print()
{
cout << "test()" <<endl;
}
};
class test1 : public test
{
};
int main()
{
test1 a1;
test t1 = a1; //子类对象可以给父类对象初始化
t1.print();
test t2;
t2 = a1; //子类对象可以给父类对象赋值
t2.print();
test* t3 = &a1; //父类对象指针指向子类对象
t3->print();
test& t4 = a1; //父类引用可以引用子类对象
t4.print();
return 0;
}
6.继承与构造析构:
a.类在c++编译器的内部可以理解为
结构体,
子类是由父类成员叠加子类新成员得到的
b.继承与构造:在子类对象
构造的时候,需要
先调用父类的构造函数对其
继承得来的成员进行初始化,如图
c.继承与析构:在子类对象
析构的时候,需要
后调用父类析构函数对其
继承得来的成员进行初始化,如图
示例代码:
#include <iostream>
using namespace std;
class test
{
protected:
int a;
public:
test()
{
cout << "test()" << endl;
}
~test()
{
cout << "~test()" <<endl;
}
};
class test1 : public test
{
public:
test1()
{
cout << "test1()" << endl;
}
~test1()
{
cout << "~test1()" << endl;
}
};
int main()
{
test1 t1;
return 0;
}
注意:第一,子类对象在创建时会首先调用父类的构造函数
第二,
父类构造函数执行结束后,执行子类的构造函数
第三,
当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
第四,
析构函数调用的先后顺序与构造函数相反
示例代码:
示例代码:
#include <iostream>
using namespace std;
class gparent
{
public:
gparent(char* s)
{
cout << "gparent() " << s << endl;
}
};
class parent : gparent
{
public:
parent(char* s) : gparent(s)
{
cout << "parent() " << s << endl;
}
};
class child : parent
{
protected:
parent p1;
parent p2;
public:
/*这条语句有点意思 本来说初始化列表在构造函数前面执行
但是在初始化列表中 竟然可以使用构造函数的形参值
所以看来初始化列表 和 构造函数的关系挺暧昧
p1(s)的意思是 初始化p1对象 如何初始化的
就是调用parent类的构造函数 即parent p1(s);
p1(" p1 ")的意思也是 初始化p1对象
也是调用parent类的构造函数 即parent p1(" p1 ");
*/
child(char* s) : parent(s) , p1(" p1 ") ,p2(" p2 ")
{
cout << "child() " << s << endl;
}
};
int main()
{
child c1("hello world");
return 0;
}
第二,
在初始化列表中,初始化其他类的对象的时候,其实是在调用其他类的构造函数,如:p1(s) 就是 parent p1(s) p1(" p1 ") 就是 parent p1(" p1 ")
第三,对于这些构造函数的调用顺序,要遵守
先父母,后客人,再自己 的原则
7.子类与父类中的同名成员变量:
a.当子类成员变量与父类成员变量同名时,
子类依然从父类继承同名成员
b.
在子类中通过作用域分别符号 :: 进行同名成员区分
c.
同名成员存储在内存中的不同位置
d.
如果在子类中不用作用域分别符号 来区分同名成员变量,默认的成员变量是子类的成员变量
示例代码:
#include <iostream>
using namespace std;
class test
{
protected :
int a;
int b;
public :
};
class t : test
{
protected :
int a;
int b;
public :
void fun()
{
a = 12;
b = 11;
cout << a << " " << b << endl;
cout << test::a << " " << test::b << endl;
cout << t::a << " " << t::b << endl;
}
};
int main()
{
t t1;
t1.fun();
return 0;
}