目录
一.继承与友元的关系
二.继承与静态成员的关系
先回顾一下静态成员变量:
运行TestPerson()函数:
测试案例2:
三.练习题:
一.继承与友元的关系
友元关系不能被继承,也就是说父类中的友元函数不能访问子类私有和保护成员
class Student;
class Person{
public:
//友元声明
friend void Display(const Person& p, const Student& s);
protected:
string _name; // 姓名
};
class Student : public Person{
public:
//...
protected:
int _stuNum; // 学号
};
void Display(const Person& p, const Student& s){
cout << p._name << endl;
//cout << s._stuNum << endl; //报错,除非让子类中也使用友元声明
}
int main(){
Person p;
Student s;
Display(p, s);
return 0;
}
如上图:友元函数Display只在父类中声明过,所以友元函数可以访问父类的成员变量,Student虽然为Person的子类,但是友元是不会被继承下来的,也就是说父辈那一代是朋友关系,但并不意味着父辈的子女与其也是朋友关系。
想让子类也能使用父类的友元函数,需要在子类中也加入友元声明!
二.继承与静态成员的关系
先回顾一下静态成员变量:
1.它并不在类对象中存放,它在静态区。
2.而且静态成员变量的创建在类内,定义是在该类的外面定义,定义时需要进行初始化赋值!!!3.一个类对象被创建时,类对象中只有类的成员变量(静态成员变量除外)!!!
4.成员函数不在类对象中!!!
5.类对象的大小是根据类的成员变量规定的大小!
总之,静态成员变量是被所有类对象所共享的,它只有一份。
class Person{
public:
Person() { ++_count; }
void Print() {
//_name = "zzz";
cout << "Print()函数" << endl;
}
public:
string _name; // 姓名
int _age;
static int _count; // 统计人的个数。
};
//父类的静态成员变量
int Person::_count = 0;
//子类
class Student : public Person{
protected:
int _stuNum; // 学号
};
//孙子类
class Graduate : public Student{
protected:
string _seminarCourse; // 研究科目
};
void TestPerson(){
Student s1;
Student s2;
Student s3;
Graduate s4;
cout << " 人数 :" << Person::_count << endl;
Student::_count = 0;
cout << " 人数 :" << Person::_count << endl;
}
在父类Person的构造函数中,每调用一次构造函数,静态成员变量_count的值就会加1。
现如今有一个继承父类的子类和一个继承子类的孙子类。
测试函数中,创建了四个对象,该静态成员变量的值为多少?
运行TestPerson()函数:
通过结果的运行可知,_count的值为4, 原因:前三个对象的创建自然不必说,都是调用自家类的构造函数,而对于孙子类Graduate的对象创建,它虽然是继承自子类Student,但是Student也是继承于Person类,它们之间有血缘关系,那么孙子类的对象创建自然也离不开父类的构造函数!!!
测试案例2:
运行结果:
通过结果可知:父类对象与子类对象的_count是同一份,无论是值还是地址都完全相同,所以推断结论:父类的静态成员变量会被子类所继承,子类使用的_count与父类的是同一个_count
而且只要一方将静态成员值修改了,那么只要与该静态成员有关的类所对应的值也都会变。
三.练习题:
class Person{
public:
Person() { ++_count; }
void Print() {
cout << "Print()函数" << endl;
}
public:
string _name; // 姓名
int _age;
static int _count; // 统计人的个数。
};
//父类的静态成员变量
int Person::_count = 0;
void Test3() {
Person *ptr=nullptr;
//代码1:
cout << ptr->_name << endl;
//代码2:
cout << ptr->_age << endl;
//代码3:
cout << ptr->_count << endl;
//代码4:
ptr->Print();
}
int main(){
Test3();
}
在Test3()函数中,执行以下每一条代码时,结果是什么
//代码1: cout << ptr->_name << endl;
//代码2: cout << ptr->_age << endl;
//代码3: cout << ptr->_count << endl;
//代码4: ptr->Print();
考题解析:
代码1的结果会出现异常,因为Person类创建的对象是指针类型的,一开始指针对象被初始化为空,该指针对象ptr中的成员变量_name值也是空的,所以当ptr访问它的成员变量_name时会出错(空指针访问成员变量会异常);代码2的结果也是异常,与代码1性质相同,都是空指针访问了其成员变量。
代码3结果正确,因为静态成员变量并不在父类对象ptr中!!!,它是在静态区存放。
代码4结果正确,因为成员函数Print也不在父类对象ptr中!!!,况且在成员函数中,并没有访问其成员变量(并没有发生空指针访问成员变量的行为),所以该对象访问成员函数行为无异常。强调:类对象中只存储非静态成员变量,所以类对象的大小由类所拥有的成员变量所决定。并且类对象不存储成员函数,也不存储静态成员变量。
若是父类的Print函数中,访问了成员变量:
那么:
Person *ptr=nullptr;
//代码4:
ptr->Print();代码4的运行就如同上面的代码1的结果一样,运行异常报错,ptr为空,虽然访问了成员函数这一步没有报错,但进入到成员函数体运行其语句时,发现执行了_name=“zzz”;语句,该语句相当于this->_name访问成员变量,类对象访问成员函数就是将该对象的地址传给类的this指针,此时this指针相当于是空指针,空指针访问成员变量,报错!!!