一、基类和派生类对象赋值转换
在public继承时,父类和子类是一个“is - a”的关系。
子类对象赋值给父类对象/父类指针/父类引用,我们认为是天然的,中间不产生临时对象,也叫作父子类赋值兼容规则(切割/切片)。
#include<iostream>
#include<string>
using namespace std;
class person
{
public:
void print()
{
cout << "name: " << _name << endl;
cout << "id: " << _id << endl;
cout << "age: " << _age << endl;
}
protected:
string _name = "zhangsan";
string _id = "111111";
int _age = 18;
};
// 继承后父类的person的成员(成员函数+成员变量)都会变成子类的一部分。
// 这里体现出了student和teacher复用了Person的成员。
class student :public person
{
private:
string _class;
};
class teacher :public person
{
private:
string _collage;
};
int main()
{
student s;
teacher t;
float a = 1.1;
//这里的赋值会产生临时变量,隐式类型转换
int b = a;
//这里必须加const,因为c指向的是所产生的临时变量,它是一个常量
const int& c = a;
person p = s;
//这里就不用加const
person& rp = t;
return 0;
}
二、继承中的作用域
父类和子类可以拥有同名成员,因为他们是独立作用域。默认情况直接访问是子类的,子类同名成员隐藏父类同名成员。此时,如果我们想要访问父类的同名成员,需指定类域。
在继承中,对于同名的成员函数,函数名相同则构成隐藏,不管参数和返回值。
#include<iostream>
#include<string>
using namespace std;
class person
{
public:
void print()
{
cout << "name: " << _name << endl;
cout << "id: " << _id << endl;
cout << "age: " << _age << endl;
}
protected:
string _name = "zhangsan";
string _id = "111111";//身份证号
int _age = 18;
};
// 继承后父类的person的成员(成员函数+成员变量)都会变成子类的一部分。
// 这里体现出了student和teacher复用了Person的成员。
class student :public person
{
public:
void print()
{
cout << "name: " << _name << endl;
cout << "身份证号: " << person::_id << endl;
cout << "学号: " << _id << endl;
cout << "age: " << _age << endl;
}
private:
string _class;
string _id = "222222";//学号
};
class teacher :public person
{
private:
string _collage;
};
int main()
{
student s;
s.print();
return 0;
}
三、派生类的默认成员函数
6个默认成员函数,“默认”的意思是指我们不写,编译器会变我们自动生成一个,那么在派生类中,这几个成员函数是如何生成的呢?
- 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显式调用。
- 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
- 派生类的operator=必须要调用基类的operator=完成基类的复制。
- 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。(保证析构安全)
- 派生类对象初始化先调用基类构造再调派生类构造。
- 派生类对象析构清理先调用派生类析构再调基类的析构。
class Person
{
public:
Person(const char* name = "aaa")
: _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:
Student(const char* name, int num)
: Person(name)
, _num(num)
{
cout << "Student()" << endl;
}
Student(const Student& s)
: Person(s)
, _num(s._num)
{
cout << "Student(const Student& s)" << endl;
}
Student& operator = (const Student& s)
{
cout << "Student& operator= (const Student& s)" << endl;
if (this != &s)
{
Person::operator =(s);
_num = s._num;
}
return *this;
}
~Student()
{
cout << "~Student()" << endl;
}
protected:
int _num; //学号
};
void Test()
{
Student s1("zhangsan", 20);
Student s2(s1);
Student s3("lisi", 23);
s1 = s3;
}
int main()
{
Test();
return 0;
}
四、补充
- 友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
- 基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例 。