🔥个人主页:guoguoqiang. 🔥专栏:我与C++的爱恋
1.派生类的默认成员函数
class Person
{
public:
Person(const char* name = "jason")
: _name(name)
{
cout << "Person()" << endl;
}
Person(const Person& p)
: _name(p._name)
{
cout << "Person(const Person& p)" << endl;
}
Person& operator=(const Person& p)
{
cout << "Person operator=(const Person& p)" << endl;
if (this != &p)
_name = p._name;
return *this;
}
~Person()
{
cout << "~Person()" << endl;
}
protected:
string _name; // 姓名
};
class Student : public Person
{
public:
protected:
int _num; //学号
};
派生类里面,把父类成员当做一个整体
派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用
Student(const char* name, int num)
: Person(name)
, _num(num)
{
cout << "Student()" << endl;
}
成员变量的初始化顺序是根据它们在类定义中出现的顺序,而不是初始化列表中的顺序。因此,基类的构造函数总是首先被调用,再是派生类中定义的成员变量
2.派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化,一般情况下默认生成的就够用,如果涉及到深拷贝,就需要自己显示实现
Student(const Student& s)
: Person(s)
, _num(s._num)
{
cout << "Student(const Student& s)" << endl;
}
3.派生类的operator=必须要调用基类的operator=完成基类的复制
Student& operator = (const Student& s)
{
cout << "Student& operator= (const Student& s)" << endl;
if (this != &s)
{
Person::operator =(s);
_num = s._num;
}
return *this;
}
4.派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序
5.派生类对象初始化:先调用基类构造再调派生类构造
6.派生类对象析构清理:先调用派生类析构再调基类的析构。
7.因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加virtual的情况下,子类析构函数和父类析构函数构成隐藏关系
如果想要显示调用就需要这样:
~Student()
{
Person::~Person();
cout << "~Student()" << endl;
}
但是这里会导致一个问题,析构多调用了一次,就是因为析构函数先调用子类再调用父类的,子类析构函数结束后会自动调用父类析构
2.继承与友元
友元关系不能继承,基类友元不能访问子类私有和保护成员
class Person
{
public:
friend void Display(const Person& p, const Student& s);
protected:
string _name; // 姓名
};
class Student : public Person
{
protected:
int _stuNum; // 学号
};
void Display(const Person& p, const Student& s)
{
cout << p._name << endl;
cout << s._stuNum << endl;
}
基类将某些函数或类声明为友元,这个友元关系不会自动传递给从派生)。派生类需要自己明确声明哪些函数或类是它的友元
class Student : public Person
{
public:
friend void Display(const Person& p, const Student& s);
protected:
int _stuNum; // 学号
};
现在,Display 函数是 Person 和 Student 两个类的友元,可以访问两个类的保护成员
3.继承与静态成员
基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例
class Person
{
public:
Person() { ++_count; }
protected:
string _name; // 姓名
public:
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;
}
静态成员是与类本身关联的,而不是与类的单个实例相关联。静态成员变量在所有实例中共享,而静态成员函数可以在没有类实例的情况下直接通过类名调用。当静态成员被继承时,派生类共享同一个静态成员副本,因为静态成员是属于类的,不属于类的任何具体对象。
静态成员的继承性质:静态成员在基类及其派生类之间是共享的,而不是每个派生类都有独立的静态成员副本。因此,无论是在基类还是派生类中访问静态成员,访问的都是同一个数据。在设计类层次结构时,这一点非常重要,因为静态成员的行为可能会影响整个类族。