继承就是可以复用class类或者struct类的代码!其中被继承的叫做基类或父类,继承的叫做子类或派生类。
基类可以给派生类赋值,而派生类不可以给基类赋值,因为在C++的设计中,基类可以进行切割或切片,将多余的部分切去,使得基类可以被赋值,具体用法如下
class Person
{
public:
void print()
{
cout << _age << "\n";
cout << _name << "\n";
}
protected:
int _age = 18;
string _name = "name";
};
class Student:public Person
{
public:
void changeNameAge(int n,string s)
{
_age = n;
_name = s;
}
private:
int _stunum;
};
int main()
{
Student s;
Person p;
//父类和子类之间的赋值规则
//子类对象可以赋值给父类对象/引用/指针
s.changeNameAge(12,"zhangsan");
p.print();
p = s;
p.print();
return 0;
}
继承中的子类和父类都有独立的作用域,其中在子类的作用域中,如果有和父类同名的函数,就会发生隐藏或重定义,不加作用域的话默认调用的就是子类的,想要调用父类的需要家父类的作用域(重载要求作用域相同,这里的作用域不同所以不构成重载)
派生类中的四个默认成员函数(其实是六个,还有两个一般用不上,所以不考虑)其中除了析构函数不需要自己去调用以外,其他三个都要显式调用,具体用法如图所示。
class Preson
{
public:
Preson(const char* s = "peter")
:_name(s)
{
cout << "构造函数:Preson" << endl;
}
~Preson();
Preson(const Preson& p);
Preson& operator=(const Preson& p);
protected:
string _name;
};
Preson::~Preson()
{
cout << "~Preson" << endl;
}
Preson::Preson(const Preson& p)
:_name(p._name)
{
cout << "拷贝构造" << endl;
}
Preson& Preson:: operator=(const Preson& p)
{
cout << "operator=" << endl;
if(this != &p)
_name = p._name;
return *this;
}
//友元无法被继承
//静态成员对象是同一个的
class Student : public Preson
{
public:
Student(const char* name, int n)
//:_name(name)//不能之间初始化
:Preson(name)
, _stuid(n)
{
cout << "Student(const char* name, int n)\n";
}
Student(const Student& s)
:Preson(s)
,_stuid(s._stuid)
{
cout << "Student(const Student& s)\n";
}
const Student& operator=(const Student& s)
{
if (this != &s)
{
Preson::operator=(s);
_stuid = s._stuid;
cout << "Student& operator=(const Student& s)\n";
}
return s;
}
~Student()
{
//~Preson();//不能这样子调用因为之后会被改成destructor
//Preson::~Preson();不需要你显示调用会自动调用
cout << "~Student" << endl;
}
protected:
int _stuid;
};
int main()
{
Student s1("jack",18);
Student s2(s1);
Student s3("bobo", 20);
s1 = s3;
return 0;
}
友元函数并不会被继承,如果需要使用需要将友元函数放到子类中。
静态成员函数会被继承,他只会在两个类中都为同一个。
要了解菱形继承首先要了解多继承,多继承就是一个子类有两个或两个以上的父类继承而来
而菱形继承是一个子类的多个父类中存在有多个父类继承于同一个类的现象就是菱形继承,他会导致代码冗余和二义性。
如果发生这种情况最好是使用virtual关键字来写在继承访问限定符前面。
使用virtual关键字会导致继承变为虚拟继承,他是通过虚拟表指针指向虚拟表,虚拟表中存放的是偏移量,用于找到共同的变量
继承是白盒复用,他对子类更加透明,但是会破坏父类的封装性
组合是黑盒复用,他对子类不透明,但是他保证了父类的封装性
继承的耦合度更高,组合耦合度更低
如果同时可以用就使用组合,如果是处理is - a问题用继承,即子类是一个父类的时候就用继承
如果处理has -a问题用组合,即子类有一个父类的时候就用组合