C++继承特性(4)——友元与静态

目录

一.继承与友元的关系

二.继承与静态成员的关系 

先回顾一下静态成员变量:

运行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指针相当于是空指针,空指针访问成员变量,报错!!!

猜你喜欢

转载自blog.csdn.net/weixin_69283129/article/details/132020442
今日推荐