继承:一个类从另一个类获取成员变量和成员函数的过程
继承的语法:类A 继承 类B
eg: class A:访问控制符 B
class Dog : public Animal
类B 就是类A 的基类,类A就是类B的派生类(子类)
继承的一些特性
1、子类拥有父类的所有成员变量和成员函数
2、子类可以拥有父类没有的方法和属性
3、子类就是一种特殊的父类
4、子类对象可以当作父类对象使用
继承的三种方式:
#include <iostream>
using namespace std;
class Parent
{
public:
int m_public;
protected:
int m_protected;
private:
int m_private;
};
//基类成员在派生类中的权限:在基类中的权限*继承是的权限 = 两者中权限较低者
// eg: public * private(class Child3 : private Parent) = private
//不管以何种方式继承,基类的私有成员在派生类中是不可使用的
/*
公有继承
1、基类中的public 成员:在派生类中还是 public 属性,在类的内部和外部都可以使用
2、基类中的protected 成员:在派生类中还是 protected 属性,在类的内部可以使用,在类的外部不可以使用
3、基类中的private 成员:在派生类中还是private 属性,在类的内部和外部都不可以使用
*/
class Child1 : public Parent
{
public:
void use()
{
m_public = 1;
m_protected = 2;
//m_private = 3;不可用
}
};
/*
保护继承
1、基类中的public 成员:在派生类中是 protected 属性,在类的内部可以使用,在类的外部不可以使用
2、基类中的protected 成员:在派生类中是 protected 属性,在类的内部可以使用,在类的外部不可以使用
3、基类中的private 成员:在派生类中还是private 属性,在类的内部和外部都不可以使用
*/
class Child2 : protected Parent
{
public:
void use()
{
m_public = 1;
m_protected = 2;
//m_private = 3;不可用
}
};
/*
私有继承
1、基类中的public 成员:在派生类中是private 属性,在类的内部和外部都不可以使用
2、基类中的protected 成员:在派生类还是 private 属性,在类的内部和外部都不可以使用
3、基类中的private 成员:在派生类中是private 属性,在类的内部和外部都不可以使用
*/
class Child3 : private Parent
{
public:
void use()
{
m_public = 1;
m_protected = 2;
//m_private = 3;不可用
}
};
//私有继承后,对Child3的子类来说,祖父类的成员都不可用
class GrandSon : public Child3
{
public:
void use()
{
//m_public = 1;不可用
//m_protected = 2;不可用
//m_private = 3;不可用
}
};
不同的继承方式会影响基类成员在派生类中的访问权限。
1) public继承方式
基类中所有 public 成员在派生类中为 public 属性;
基类中所有 protected 成员在派生类中为 protected 属性;
基类中所有 private 成员在派生类中不能使用。
2) protected继承方式
基类中的所有 public 成员在派生类中为 protected 属性;
基类中的所有 protected 成员在派生类中为 protected 属性;
基类中的所有 private 成员在派生类中不能使用。
3) private继承方式
基类中的所有 public 成员在派生类中均为 private 属性;
基类中的所有 protected 成员在派生类中均为 private 属性;
基类中的所有 private 成员在派生类中不能使用。
通过上面的分析可以发现:
1) 基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如,当继承方式为 protected 时,那么基类成员在派生类中的访问权限最高也为 protected,高于 protected 的会降级为 protected,但低于 protected 不会升级。再如,当继承方式为 public 时,那么基类成员在派生类中的访问权限将保持不变。
也就是说,继承方式中的 public、protected、private 是用来指明基类成员在派生类中的最高访问权限的。
2) 不管继承方式如何,基类中的 private 成员在派生类中始终不能使用(不能在派生类的成员函数中访问或调用)。
3) 如果希望基类的成员能够被派生类继承并且毫无障碍地使用,那么这些成员只能声明为 public 或 protected;只有那些不希望在派生类中使用的成员才声明为 private。
4) 如果希望基类的成员既不向外暴露(不能通过对象访问),还能在派生类中使用,那么只能声明为 protected。
注意,我们这里说的是基类的 private 成员不能在派生类中使用,并没有说基类的 private 成员不能被继承。实际上,基类的 private 成员是能够被继承的,并且(成员变量)会占用派生类对象的内存,它只是在派生类中不可见,导致无法使用罢了。private 成员的这种特性,能够很好的对派生类隐藏基类的实现,以体现面向对象的封装性。
类的对象模型
派生类的内存模型:基类成员放在前面,派生类自己的成员跟在后面进行排列。
类型兼容规则:是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。类型兼容规则中所指的替代包括以下情况:
1、派生类成员对象可以代替基类成员对象
2、基类指针可以指向(操作)派生类对象(指针指向派生类对象的内存中与基类内存模型相同的部分)
3、基类的引用可以直接引用派生类对象
4、派生类对象可以直接对基类对象进行初始化和赋值
#include <iostream>
using namespace std;
class Parent
{
public:
Parent(){}
Parent(const Parent &p)
{
cout << "Parnt 的拷贝构造" << endl;
a1 = p.a1;
a2 = p.a2;
}
void setP(int a, int b)
{
a1 = a;
a2 = b;
}
void showP()
{
printf("a1 = %d, a2 = %d\n", a1, a2);
}
public:
int a1;
int a2;
};
class Child:public Parent
{
public:
void setC(int a, int b)
{
b1 = a;
b2 = b;
}
void showC()
{
printf("b1 = %d, b2 = %d\n", b1, b2);
}
public:
int b1;
int b2;
};
//1、派生类对象可以代替基类成员对象
void func1()
{
Parent p1;
Child c1;
/*
p1.setP(1,2);
p1.showP()
*/
c1.setP(1,2);
c1.showP();
p1.showP();
}
//2、基类指针可以指向(操作)派生类对象
void show(Parent *p)
{
p->showP();
}
void func2()
{
//派生类对象
Child c1;
//基类指针
//指针的操作限制于自身的类型 并不关心指向的是什么东西
//指针是什么类型解只能做该类型所能做的事情,和指向的对象类型无关
//p1 是Parent 类型, 所以只能做 Parent能做的事情
//虽然它指向的是一个派生类对象,但它 还是认为那个对象是一个 Parent类型的对象
Parent *p1 = &c1;
p1->setP(3,4);
p1->showP();
Child c2;
c2.setP(5,6);
Parent p2;
p2.setP(7,8);
show(&c2);
show(&p2);
}
//3、基类的引用可以直接引用派生类对象:引用的本质是常指针
void func3()
{
Child c1;
Parent &p1 = c1;//Parent *const p1 = &c1;基于性质2 基类指针可以指向(操作)派生类对象
p1.setP(1,2);
c1.showP();
}
//4、派生类对象可以直接对基类对象进行初始化、赋值
void func4()
{
Child c1;
c1.setP(1,2);
c1.setC(3,4);
//用对象 c1 对 p1 进行初始化
//Parent (const Parent &p)Parent的拷贝构造函数
Parent p1 = c1;//调用拷贝构造函数
Parent p2;
p2 = c1;//赋值
}
int main()
{
//func1();
//func2();
//func3();
func4();
return 0;
}