#include <iostream>
using namespace std;
class Person
{
protected:
string _name;
string _sex;
int _age;
};
class Student :public Person
{
public:
int _No;
};
int main()
{
Person p;
Student s;
//子类和父类之间赋值兼容规则
//1、子类对象可以赋值父类对象/指针/引用
p = s;
Person* p1 = &s;
Person& p1 = s;
return 0;
}
不同作用域(隐藏(重定义))
class Person
{
protected:
string _sex;
int _age=111;
};
class Student :public Person
{
public:
void f()
{
cout << _age << endl;
}
public:
int _age=99;
};
int main()
{
Student s;
s.f();
}
面向对象的三大特性
封装(类的封装)、继承、多态
实际上面向对象不只三大特性
派生类的默认成员函数
如何在子类中初始化父类部分呢?
假设1:
假设2:
如何完成子类拷贝构造呢?
什么是拷贝构造?
1、拷贝构造的参数只有一个,该参数的类型是对象类型的引用,为什么要引用?因为防止无限的调用拷贝构造去递归,一般用const修饰
2、要区分深拷贝和浅拷贝的问题,系统默认生成的拷贝函数的内存存储方式是字节序存储所以要注意成员变量类型的,防止释放两次同一个空间
复习完成
class Person
{
public:
Person(const char*name="")
:_name(name)
{
cout <<_name << "Person()" << endl;
}
Person(const Person& p1)
:_name(p1._name)
{
cout << "Person(const Person& p1)" << endl;
}
private:
string _name;
};
class Student :Person
{
public:
Student(const char*name,int id)
:Person(name),//要以父类名()的方式调用父类构造函数初始化子类中的父类部分
_stuid(id)
{
cout << "student()" << endl;
}
Student(const Student& s1)
:Person(s1)//要以父类名()的方式调用父类的拷贝构造函数 复制子类中的父类部分
{
_stuid = s1._stuid;
cout << "Student(const Student& s1)" << endl;
}
private:
int _stuid;
};
int main()
{
//Person p1("aaa");
Student s1("bbb",9);//初始化
Student s2(s1);//拷贝构造
//Student s3 ("gg",30);//初始化
//s1 = s3;//s1.operator=(s3)
return 0;
}
子类的operator=:
class Person
{
public:
//初始化
Person(const char*name="")
:_name(name)
{
cout <<_name << "Person()" << endl;
}
//拷贝
Person(const Person& p1)
:_name(p1._name)
{
cout << "Person(const Person& p1)" << endl;
}
//父类的operator=函数
Person& operator=(const Person& s1)
{
if (this != &s1)
{
_name = s1._name;
cout << "Person& operator=(const Person& s1)" << endl;
}
return *this;
}
private:
string _name;//string(const char*s1)
};
class Student :Person
{
public:
Student(const char*name,int id)
:Person(name),
_stuid(id)
{
cout << "student()" << endl;
}
Student(const Student& s1)
:Person(s1)//要以父类名()的方式调用父类的拷贝初始化子类中的父类部分
{
_stuid = s1._stuid;
cout << "Student(const Student& s1)" << endl;
}
//operator=
Student& operator=(const Student& s1)
{
if (this != &s1)//防止赋值时,两个对象时一个对象,浪费时间
{
Person::operator=(s1);//显示调用父类的operator=,将父类的部分赋值
_stuid = s1._stuid;
cout << "Student& operator=(const Student& s1)" << endl;
}
return *this;//返回子类的对象
}
private:
int _stuid;
};
int main()
{
//Person p1("aaa");
Student s1("bbb",9);//初始化
Student s2(s1);//拷贝构造
//Student s3 ("gg",30);//初始化
//s1 = s3;//s1.operator=(s3)
return 0;
}
子类的析构函数
面试题
如何构建一个不可以继承的类
#include <iostream>
using namespace std;
class A
{
private: //将父类的初始化私有化
A()
{
}
}
class B:public A
{
}
int main()
{
B b;//初始化不了对象
return 0;
}
友元关系不能被继承(了解就好)
会报错,要是想用只可以手动添加
静态成员在父类中被继承会发生什么?
class Person
{
public:
Person()
{
_count++;
}
public:
string _name;
static int _count;
};
int Person::_count = 0;//静态成员必须初始化
class Student:public Person
{
public:
private:
int id;
};
int main()
{
Person p1;
Student s1;
p1._name = "jack";
s1._name = "rose";
p1._count = 1;
s1._count = 2;
cout << Person::_count << endl;//静态成员属于对象也属于类所以可以Person::_count
return 0;
}
多继承
多继承会造成很多问题的,所以后来的语言是没有多继承的,多继承是一个大坑
为什么是大坑?
class Person
{
public:
string _name; // 姓名
};
class Student : public Person
{
protected:
int _num; //学号
};
class Teacher : public Person
{
protected:
int _id; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected:
string _majorCourse; // 主修课程
};
void Test()
{
// 这样会有二义性无法明确知道访问的是哪一个
Assistant a;
a._name = "peter";//菱形继承会导致二义性不知道是那个的_name
// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
a.Student::_name = "xxx";
a.Teacher::_name = "yyy";
}
菱形继承:
菱形继承原理
experiment:
class A
{
public:
int _a;
};
class B:public A
{
public:
int _b;
};
class C :public A
{
public:
int _c;
};
class D:public B , public C
{
public:
int _d;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
return 0;
}
进入调试看内存
这是内存模型,存在数据冗余和二义性
但是我们要看虚继承的内存模型
using namespace std;
class A
{
public:
int _a;
};
class B:virtual public A//添加了virtual
{
public:
int _b;
};
class C :virtual public A
{
public:
int _c;
};
class D:public B , public C
{
public:
int _d;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
return 0;
}
进入调试内存
接下来看看这些是什么?
好像是地址
再次进入内存
为什么要设计出来呢?
菱形继承:
虚继承:
为什么虚继承会比菱形继承还大呢?
是因为多了两个指针
我相信很多同学会问不是解决数据冗余吗?为什么越来越大了
因为基类太小了
菱形继承:
虚继承:
少了一倍
这就是虚继承的基本概念