源代码:
#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; } };