一、继承访问权限测试
源代码:
#include <iostream>
using namespace std;
class A_animal{
public:
void eat(){
cout << "need eat" << endl;
}
protected:
void sleep(){
cout << "need sleep" << endl;
}
private:
void stand(){
cout << "can stand up" << endl;
}
};
//这里子类B_dog可以通过公有继承、保护继承、私有继承来继承父类A_animal
class pub_B_dog : public A_animal{
public:
void pub_test(){
eat();//可以访问
sleep();//只有在派生类中利用派生类对象访问基类中protected对象
//stand();//不能访问
}
void pub_bark(){
cout << "wangwang(pub)" << endl;
}
protected:
void pub_tail(){
cout << "short tail(pub)" << endl;
}
private:
void pub_hair(){
cout << "yellow(pub)" << endl;
}
};
class pro_B_dog : protected A_animal{
public:
void pro_test(){
eat();//可以访问
sleep();//只有在派生类中利用派生类对象访问基类中protected对象
//stand();//不能访问
}
void pro_bark(){
cout << "wangwang(pro)" << endl;
}
protected:
void pro_tail(){
cout << "short tail(pro)" << endl;
}
private:
void pro_hair(){
cout << "yellow(pro)" << endl;
}
};
class pri_B_dog : private A_animal{
public:
void pri_test(){
eat();//可以访问
sleep();//只有在派生类中利用派生类对象访问基类中protected对象
//stand();//不能访问
}
void pri_bark(){
cout << "wangwang(pri)" << endl;
}
protected:
void pri_tail(){
cout << "short tail(pri)" << endl;
}
private:
void pri_hair(){
cout << "yellow(pri)" << endl;
}
};
int main()
{
pub_B_dog A;
A.pub_bark();//派生类能访问基类中public成员
A.eat();
//A.sleep();//派生类不能访问基类中protected成员
//A.stand();//派生类不能访问基类中private成员
//A.pub_tail();
//A.pub_hair();
pro_B_dog B;
B.pro_bark();
//B.eat();
//B.sleep();
//B.stand();
//B.pro_tail();
//B.pro_hair();
pri_B_dog C;
C.pri_bark();
//C.eat();
//C.sleep();
//C.stand();
//C.pri_tail();
//C.pri_hair();
return 0;
}
1.public、protected、private三种继承的派生类可以访问基类中的public、protected 成员;
2.基类中的private 成员不可以在派生类中被直接访问;
3.派生类对象仅当 public 派生时,对基类中的 public 成员有可访问/可修改的权限,其他都为不可访问/不可修改。
4.继承方式会改变从基类继承的成员在派生类的访问权限:
? ? ?(1).public 继承不改变基类成员的访问权限
? ? ?(2).protected 继承将基类中 public 成员变为子类的 protected 成员,其它成员的访问权限不变
? ? ?(3).private 继承使得基类所有成员在子类中的访问权限变为 private
5.B以private方式继承A,用{using A::_a; }把A中的部分public成员提升为public
6.如果想让这些继承而来的数据成员作为public或者protected成员,可以用using重新声明。using声明语句中名字的访问权限由该using声明语句之前的访问说明符决定。
二、友元类继承测试
源代码:
#include<istream>
using namespace std;
class A {
private:
int a;
friend class C;//友元类给类C;
};
class B: public A {
private:
int b;
};
class C {
public:
void Test() {
B b1;
b1.a;
//b1._b;不可访问 ;
}
};
class D :public C {
public:
void Test() {
A a1;
//a1.a;//不可访问;
B b2;
//b2.a;//不可访问 ;
//b2.b;//不可访问 ;
}
};
1.友元关系不能继承。基类的友元对派生类的成员没有特殊访问权限。
2.如果基类被授予友元关系,则只有基类具有特殊访问权限,该基类的派生类不能访问授予友元关系的类。当类Y被说明为类X的友元时,类Y的所有成员函数都成为类X的友元函数,这就意味着作为友元类Y中的所有成员函数都可以访问类X中的所有成员(包括私有成员)。
3.友元关系是单向的,不具有交换性。友元关系也不具有传递性。友元关系不能被继承,基类的友元类未必是子类的友元,某类型的友元的子类未必是该类型的友元。
三、多态性的综合应用
1.一般多态性:
新建CAnimal类,Move()是其内部虚函数,新建CCat类、CEagle类、COwl类继承CAnimal类,并重写其内部的虚函数Move()的实现方法以实现多态的效果。
#include <iostream>
using namespace std;
class CAnimal
{
public:
//无参构造函数
CAnimal() {
m_nLegs = 2;
}
CAnimal(int nLeg) {
m_nLegs = nLeg;
}
//虚函数
virtual void Move() {
cout << "I can crawl or fly!" << endl;
}
protected:
int m_nLegs;
};
class CCat : virtual public CAnimal
{
public:
//无参构造函数
CCat() {
m_nLegs = 4;
}
CCat(int nLegs) {
m_nLegs = nLegs;
}
virtual void Move() {
cout << "I am a cat,I can crawl!" << endl;
}
};
class CEagle : virtual public CAnimal
{
public:
//无参构造函数
CEagle() {
m_nLegs = 2;
}
CEagle(int nLegs) {
m_nLegs = nLegs;
}
virtual void Move() {
cout << "I am an eagle,I can fly!" << endl;
}
};
class COwl : public CCat, public CEagle
{
public:
//无参构造函数
COwl() {
m_nLegs = 2;
}
COwl(int nLegs) {
m_nLegs = nLegs;
}
virtual void Move() {
cout << "I am an owl,I can also fly!" << endl;
}
};
void TestAnimal()
{
CAnimal* pAnimal[4];
pAnimal[0] = new CAnimal(2);
pAnimal[1] = new CCat(4);
pAnimal[2] = new CEagle(2);
pAnimal[3] = new COwl(2);
for (int i = 0; i < 4; i++)
{
pAnimal[i]->Move();
}
}
int main() {
TestAnimal();
return 0;
}
?2.特殊多态性
输入或输出参数在子类中是父类的指针或基类的引用,在子类中对于的是子类的指针或子类的引用
此处的特殊多态性含义为函数的参数是父类的指针(引用)或者子类的指针(引用)(即在运行过程中实现虚函数的绑定(运行时多态))。
#include <iostream>
using namespace std;
class CAnimal
{
public:
//无参构造函数
CAnimal() {
m_nLegs = 2;
}
CAnimal(int nLeg) {
m_nLegs = nLeg;
}
//虚函数
virtual void Move() {
cout << "I can crawl or fly!" << endl;
}
protected:
int m_nLegs;
};
class CCat : virtual public CAnimal
{
public:
//无参构造函数
CCat() {
m_nLegs = 4;
}
CCat(int nLegs) {
m_nLegs = nLegs;
}
virtual void Move() {
cout << "I am a cat,I can crawl!" << endl;
}
};
class CEagle : virtual public CAnimal
{
public:
//无参构造函数
CEagle() {
m_nLegs = 2;
}
CEagle(int nLegs) {
m_nLegs = nLegs;
}
virtual void Move() {
cout << "I am an eagle,I can fly!" << endl;
}
};
class COwl : public CCat, public CEagle
{
public:
//无参构造函数
COwl() {
m_nLegs = 2;
}
COwl(int nLegs) {
m_nLegs = nLegs;
}
virtual void Move() {
cout << "I am an owl,I can also fly!" << endl;
}
};
void callMove(CAnimal* pAn) {
pAn->Move();
}
void TestAnimal()
{
CAnimal animal;
CEagle eagle;
COwl owl;
CCat cat;
callMove(&animal);
callMove(&eagle);
callMove(&owl);
callMove(&cat);
}
int main() {
TestAnimal();
return 0;
}
?3.析构多态性
在应用C++的多态性时,当指向基类的指针被释放时,派生类的析构函数其实没有被调用,导致在派生类中申请的空间没有被释放,导致内存泄漏。
#include <iostream>
using namespace std;
class Base {
public:
Base() {cout << "Base constructor... \n";}
~Base() {cout << "Base destructor... \n";}
virtual void fun() const {cout << "Base functoin...\n";}
};
class Derived :public Base {
public:
Derived() {
p = new int(0);
cout << "Derived Constructor...\n";
}
~Derived() {
cout << "Derived destructor...\n";
delete p;
}
void fun() const {cout << "Derived function...\n";}
private:
int *p;
};
int main() {
Base* pd = new Derived;
pd->fun();
delete pd;
return 0;
}
运行结果:
?
上面运行结果显示,派生类的析构函数没有调用,派生类的构造函数申请的空间泄露了,所以可将代码改成以下代码:
class Base {
public:
Base() {cout << "Base constructor... \n";}
virtual ~Base() {cout << "Mammal destructor... \n";}
virtual void fun() const {cout << "Base functoin...\n";}
};
?运行结果:
?通过将基类的析构函数声明为虚析构函数,成功的通过基类指针调用了派生类的析构函数,完成了内存的释放。
4.多继承
多继承概念:如果一个派生类从多个基类继承,则成为多继承。
多继承的声明:
class派生类名:访问控制 基类名1,访问控制 基类名2,....{
? ? ? ? 成员列表
}
需要注意以下几个点:
1.多个基类的派生类的构造函数执行的顺序与单继承的情况类似,执行顺序取决于定义派生类时指定的继承基类的顺序。 2.一个派生类对象拥有多个基类的成员。 不同名成员访问不会出现二义性; 如果不同的基类拥有同名成员, 派生类对象访问时应该加以识别。 3.如果派生类声明了一个和基类成员同名的新成员, 派生的新成员就覆盖了基类同名成员, 直接使用成员名只能访问到派生类的成员。
class A
{
public:
int a;
};
class B : public A
{
public:
int b;
};
class C : public A
{
public:
int c;
};
class D :public B, public C
{
public:
int d;
void fun()
{
d = a;
}
};
|