C++中的继承(3)作用域与重定义,赋值兼容规则

来源:互联网 发布:tensorflow tutorial 编辑:程序博客网 时间:2024/06/07 02:02

作用域与重定义(同名隐藏)

一样的,先上代码

复制代码
 1 class A 2 { 3 public: 4     int a_data; 5     void a() 6     { 7         cout << "A" << endl; 8     } 9 };10 class B11 {12 public:13     int b_data;14     void b()15     {16         cout << "B" << endl;17     }18 };19 class C :public A, public B20 {21 public:22     int c_data;23     void a(int data)//重载A类中的a()函数24     {25         cout << "C" << endl;26     }27 };28 int main()29 {30     C c;31     c.a();32     return 0;33 }
复制代码

编译后,编译器会报错错误表明:编译器并没有将c.a()看做C类继承自A类的a()函数,而是报错没有给a函数参数,即不构成函数重载,如果给c.a(10)一个参数,编译通过。输出:C

那么我们不给C类中定义同名函数呢

复制代码
 1 class A 2 { 3 public: 4     int a_data; 5     void a() 6     { 7         cout << "A" << endl; 8     } 9 };10 class B11 {12 public:13     int _data;14     void b()15     {16         cout << "B" << endl;17     }18 };19 class C :public A, public B20 {21 public:22     int _data;23     //void a(int data)24     //{25     //  cout << "C" << endl;26     //}27 };28 int main()29 {30     C c;31     c.a();32     return 0;33 }
复制代码

编译通过,运行输出:A 

以上两个例子,完全可以说明,当我们在派生类中定义一个同名函数的时候,编译器是将同名函数隐藏了,不管参数表是否相同。即不会构成函数重载,直接为函数覆盖。 
那么问题来了,为什么不会构成函数重载呢? 
一定要注意,函数重载的条件是在同一个作用域中才会构成函数重载,而派生类和基类是两个类域,一定不会构成函数重载的。

当然,我们还有另外一个方法访问同名时基类中的成员即

复制代码
 1 int main() 2 { 3     C c; 4         c._data; 5         c.B::_data; 6     c.a(); 7         c.A::a(); 8     getchar(); 9     return 0;10 }
复制代码

B类的成员变量_data与C类中的成员变量_data也构成同名隐藏。

1. 在继承体系中基类和派生类是两个不同作用域。

2. 子类和父类中有同名 成员 , 子类成员 将屏蔽父类对成员 的直接访问。 ( 在子类成员 函数中, 可以 使用 基类: : 基类成员 访问) --隐藏 --重定义

3. 注意在实际中在继承体系里面最好不要定义同名 的成员 。

 继承与转换——赋值兼容规则(public继承为例)

派生类和基类之间的特殊关系为:

1.派生类对象可以赋值给基类对象 ;基类对象不能赋值给派生类。
2.基类指针可以在不进行显示类型转换的情况下指向派生类对象 。
3.基类引用可以再不进行显示类型转换的情况下引用派生类对象,但是基类指针或引用只能用于调用基类的方法,不能用基类指针或引用调用派生类的成员及方法。

复制代码
 1 void FunTest(const Base&d) 2 {} 3 void FunTest1(const Derive&d) 4 {} 5 int main() 6 { 7     Derive d; 8     Base b(0); 9     b = d;//可以10     d = b;//不行,访问的时候会越界11     //上面已经解释过了12     FunTest(b);13     FunTest(d);14     FunTest1(b);    //报错15     FunTest1(d);16     Base* pBase = &d;   //父类指针/或引用可以直接指向子类对象,但只能访问子类中继承父类的部分17     Derive* pD = &b;//报错 子类的指针/引用不能直接指向父类对象18     //如果非要这么做只能通过强制类型转换19     Derive* pD = (Derive*)&b;//如果访问越界,程序会崩溃20 }
复制代码

   通常,C++要求引用和指针类型与赋给的类型匹配,但这一规则对继承来说是个例外。但是这个例外是单向的,即仅仅不可以将基类对象和地址赋给派生类引用和指针。如果允许基类引用隐式的引用派生类对象,则可以使用基类引用为派生类对象调用基类的方法,因为派生类继承了基类的方法,所以这样不会出现问题。但是如果可以将基类对象赋给派生类引用,那么派生类引用能够为积累对象调用派生类方法,这样做会出现问题,例如:用基类对象调用派生类中新增的方法,是没有意义的,因为基类对象中根本没有派生类的新增方法。 

友元与继承

复制代码
 1 class Person 2 { 3     friend void Display(Person &p, Student&s); 4 protected: 5     string _name; // 姓名 6 }; 7 class Student : public Person 8 { 9     protected :10     int _stuNum; // 学号11 };12 void Display(Person &p, Student &s)13 {14     cout << p._name << endl;15     cout << s._name << endl;16     cout << s._stuNum << endl;17 }18 void TestPerson1()19 {20     Person p;21     Student s;22     Display(p, s);23 }
复制代码

友元关系不能继承, 也就是说基类友元不能访问子类私有和保护成员 。友元只是能访问指定类的私有和保护成员的自定义函数,不是被指定类的成员,自然不能继承。

使用友元类时应该注意:

(1) 友元关系不能被继承。 
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。 

(3)友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明 

(4)友元可以访问类的私有成员。 
(5)友元只能出现在类定义内部,友元声明可以在类中的任何地方,一般放在类定义的开始或结尾。 
(6)友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。 
(7)类必须将重载函数集中每一个希望设为友元的函数都声明为友元。 
(8)友元关系不能继承,基类的友元对派生类的成员没有特殊的访问权限。如果基类被授予友元关系,则只有基类具有特殊的访问权限。该基类的派生类不能访问授予友元关系的类。
继承与静态成员

   了解这个问题之前,我们先确定一件事情,那就是,在基类和派生类中,静态成员和静态成员函数共用同一段空间。 我们在以前的学习过程中都知道,类的模型是所有对象的数据成员单独存储,但是所有成员函数和静态成员是共用一段空间的

复制代码
 1 class Person 2 { 3 public : 4 Person() {++ _count; } 5 protected : 6 string _name ; // 姓名 7 public : 8 static int _count; // 统计人的个数。 9 } ;10 int Person: : _count = 0;11 class Student : public Person12 {13 protected :14 int _stuNum ; // 学号15 } ;16 class Graduate : public Student17 {18 protected:19 string _seminarCourse; // 研究科目20 } ;21 void TestPerson1()22 {23 Student s1;24 Student s2;25 Student s3;26 Graduate s4;27 cout<<"人数: "<<Person: : _count<<endl;28 Student : : _count = 0;29 cout<<"人数: "<<Person: : _count<<endl;30 }
复制代码

   基类定义了 static成员 , 则整个继承体系里面只 有一个这样的成员 。 无论派生出多少个子类, 都只有 一个static成员 实例。父类的static变量和函数在派生类中依然可用,但是受访问性控制(比如,父类的private域中的就不可访问)。而且对static变量来说,派生类和父类中的static变量是共用空间的,这点在利用static变量进行引用计数的时候要特别注意。派生类的friend函数可以访问派生类本身的一切变量,包括从父类继承下来的protected域中的变量。但是对父类来说,他并不是friend的。

0 0
原创粉丝点击