1.继承的概念及定义
继承的概念:
继承是在原有类的基础上增加代码,加入一些操作方法或功能,形成一个新的类的方法;继承机制是面向对象程序设计中使代码可以复用的重要方法。
在继承机制中,将原有的类称为基类(父类),将产生的新类称为派生类(子类);
继承定义:
- 定义格式:
- 继承关系和访问限定符:
- 访问权限和继承权限作用下的访问方式的变化:
1.基类的private成员在派生类中无论以何种方式继承都是不可见的。(不可见指的是不能访问,但是派生类还是继承到了这些成员);
2.通过上表可知,基类的私有成员在派生类中都是不可见的。基类的其他成员在派生类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
3.使用关键字class时的默认继承方式时private,使用struct时默认的继承方式时public;
2.基类和派生类对象赋值转换
- 派生类对象可以赋值给基类对象/基类指针/基类引用。将这种复制方法形象的称为"切片"或者“切割”;
class Person
{
protected:
string _name;
string _sex;
int _age;
};
class Student :public Person
{
private:
int _id;
};
void Test()
{
Student s;//派生类对象
Person p = s;//派生类对象可以赋值给基类对象
Person* pptr = &s;//派生类对象可以赋值给基类指针
Person& pref = s;//派生类对象可以赋值给基类引用
}
- 基类对象不可以赋值给派生类对象;
class Person
{
protected:
string _name;
string _sex;
int _age;
};
class Student :public Person
{
private:
int _id;
};
void Test()
{
Person p;//基类对象
//Student s = p;
//基类对象不可以赋值给派生类对象;
}
- 基类的指针可以通过强制类型转换赋值给派生类指针;
class Person
{
protected:
string _name;
string _sex;
int _age;
};
class Student :public Person
{
public:
int _id;
};
void Test()
{
Person* pptr;//基类对象
Student s;//派生类对象
pptr = &s;
Student* ps = (Student*)pptr;//基类的指针可以通过强制类型转换赋值给派生类指针;
}
3.继承中的作用域(同名隐藏)
- 在继承过程种,基类和派生类都有自己独立的作用域;
- 如果基类和派生类中有同名的成员,派生类成员将隐藏基类对同名成员的直接访问, 将这种情况称为同名隐藏;
- 同名隐藏时,想要访问基类的同名成员,可以用 基类::基类成员 显式访问;
class Base
{
public:
void Test()
{
cout << "Base::Test()" << endl;
}
};
class Derived :public Base
{
public:
void Test()
{
cout << "Derived::Test()" << endl;
}
};
int main()
{
Derived d;
d.Test();
d.Base::Test();
return 0;
}
4.派生类的默认成员函数
六个默认成员函数:在类中,如果没有显式的给出这六个成员函数,编译器就会给出默认的成员函数;这六个成员函数包括:构造函数,拷贝构造函数,赋值运算符重载函数,取地址操作符重载函数,const修饰的取地址操作符重载函数和析构函数。
那么派生类的默认成员函数是如何生成的?
- 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分,如果基类没有默认构造函数,则必须在派生类的构造函数的初始化列表阶段显式调用;
- 派生类的拷贝构造函数必须调用基类的拷贝构造函数来完成基类的拷贝初始化;
- 派生类的operator=函数必须调用基类的operator=函数来完成基类的复制;
- 派生类的析构函数会在被调用完成后自动调用基类的析构函数来清理基类成员。(因为这样才能保证派生类对象先清理派生类成员在清理积累成员的顺序);
- 派生类对象初始化先调用基类构造再调用派生类构造;
- 派生类对象析构先调用派生类析构再调用基类析构;
class Person
{
public:
Person(const char* name)
:_name(name)
{
cout << "Person()" << endl;
}
Person(const Person& p)
:_name(p._name)
{
cout << "Person(const Person&)" << endl;
}
Person& operator=(const Person& p)
{
cout << "Person& operator=(const Person&)" << 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 id)
:Person(name)
, _id(id)
{
cout << "Student()" << endl;
}
Student(const Student& s)
:Person(s)
, _id(s._id)
{
cout << "Student(const Student&)" << endl;
}
Student& operator=(const Student& s)
{
cout << "Student& operator=(const Student& s)" << endl;
if (this != &s)
{
Person::operator=(s);
_id = s._id;
}
return *this;
}
~Student()
{
cout << "~Student()" << endl;
}
protected:
int _id;
};
void Test()
{
Student s1("RC", 1);
Student s2(s1);
Student s3("RRCC",10);
s1 = s3;
}
int main()
{
Test();
return 0;
}
5.继承与友元和静态成员
- 友元关系不能继承;
基类友元不能访问子类私有和保护成员;
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;
}
int main()
{
Person p;
Student s;
Display(p, s);
}
- 一个静态成员在整个继承体系中只有一个;
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 Test()
{
Student s1;
Student s2;
Student s3;
Graduate g1;
Person p1;
cout << "人数:" << Person::_count << endl;
Person::_count = 0;
cout << "人数:" << Person::_count << endl;
}
int main()
{
Test();
return 0;
}
6.三种继承关系
-
单继承:
一个子类只有一个直接父类时,称这种继承关系为单继承; -
多继承:
一个子类有两个或两个以上的直接父类时,称这种继承关系为多继承; -
菱形继承:
菱形继承是多继承的一种特殊情况;
菱形继承有数据冗余和二义性的问题;(该问题将在后边的博客中解决)
keep Running