在C++中,继承是一种面向对象编程的重要概念,它允许一个类(称为派生类)从另一个类(称为基类)继承属性和方法。通过继承,派生类可以重用基类的代码,并且可以在基础上添加或修改功能。
class Person
{
public:
void Print()
{
cout << _name << _age << endl;
}
string _name = "";
int _age = 1;
};
class Student : public Person
{
private:
int _id = 0; //学号
};
总结:
class Person
{
public:
void Print()
{
cout << _name << " " << _age << endl;
}
protected:
string _name = "张三";
private:
int _age = 1;
};
//class Student : public Person // 输出张三 1
//class Student : protected Person //编译不通过
class Student : private Person //编译不通过
{
private:
int _id = 0; //学号
};
int main()
{
Student s1;
s1.Print();
return 0;
}
派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。形象的说法叫做切片或者切割
class Person
{
public:
void Print()
{
cout << _name << " " << _age << endl;
}
protected:
string _name = "张三";
int _age = 1;
};
class Student : public Person // 输出张三 1
{
private:
int _id = 0; //学号
};
int main()
{
Student s1;
Person p1;
p1 = s1;
return 0;
}
记住一定是派生类给基类赋值才能这样!另外保护继承也不能这样
class Person
{
public:
void Print()
{
cout << _name << " " << _age << endl;
}
protected:
string _name = "张三";
int _age = 1;
};
class Student : public Person // 输出张三 1
{
public:
void Print()
{
cout << _id << " " << _name << " " << _age << endl;
}
private:
int _id = 0; //学号
};
int main()
{
Student s1;
s1.Print();
s1.Person::Print();
return 0;
}
输出结果:
class Person
{
public:
Person(string name, int age)
:_name(name)
, _age(age)
{
cout << "Person(string name, int age)" << endl;
}
Person(const Person& p)
:_name(p._name)
,_age(p._age)
{
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;
}
void Print()
{
cout << _name << " " << _age << endl;
}
protected:
string _name = "张三";
int _age = 1;
};
class Student : public Person // 输出张三 1
{
public:
Student(string name, int age, int id)
:Person(name,age)
,_id(id)
{
cout << "Student(string name, int age, int id);" << endl;
}
Student(const Student& s)
:Person(s) //这里能用Student赋值,是因为上面讲过的赋值转换
, _id(s._id)
{
cout << "Student(const Student& s);" << endl;
}
Student& operator = (const Student& s)
{
cout << "Student& operator= (const Student& s)" << endl;
if (this != &s)
{
Person::operator =(s);//这里必须使用基类的运算符重载
//因为派生类函数名和基类函数名相同构成了隐藏
_id = s._id;
}
return *this;
}
void Print()
{
cout << _id << " " << _name << " " << _age << endl;
}
~Student()
{
cout << "~Student()" << endl;
}
private:
int _id = 0; //学号
};
int main()
{
Student s1("jkl",18,006);
Student s2(s1);
Student s3("xxx",19,121);
s3 = s1;
return 0;
}
总结:
class Student;
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);
return 0;
}
其中原因是友元关系是不能继承的,也就是说Student是没有继承到友元函数的,也就导致了Student的成员不能被访问。
class Person
{
public:
Person()
{
cout << "Person()" << endl;
++_count;
}
static int _count;
protected:
string _name; // 姓名
};
int Person::_count = 0;
class Student : public Person
{
public:
Student()
{
cout << "Student()" << endl;
}
protected:
int _stuNum; // 学号
};
int main()
{
Person p;
Student s;
cout << Person::_count << endl;
return 0;
}
输出结果:
主函数只有一个Person和一个Student,但是_count却是2.
原因是:**基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。**无论派生出多少个子
类,都只有一个static成员实例
以上这种继承叫做单继承,所有的子类只有一个直接的父类。
一个子类有两个或以上直接父类时称这个继承关系为多继承。
菱形继承是多继承的一种特殊情况
菱形继承的问题:菱形继承有数据冗余和二义性的问题。在D的对象中A成员会有两份。
这里主要的问题是二义性和数据的冗余问题。
class A
{
public:
int _a = 1;
};
class B : public A
{
public:
int _b = 2;
};
class C : public A
{
public:
int _c = 3;
};
class D : public B, public C
{
public:
int _d = 4;
};
int main()
{
D d;
cout << d._d << endl;
cout << d._a << endl;
return 0;
}
编译结果:
可以通过显示访问父类成员的方式解决。
int main()
{
D d;
cout << d._d << endl;
cout << d.B::_a << endl;
cout << d.C::_a << endl;
return 0;
}
输出结果:
但是这样做并没有解决数据冗余的问题。所以就有了虚拟继承。
在B和C对A的继承使用虚拟继承就可以解决问题。
下面从内存的角度看虚拟继承
其中B和C存的另一个地址是A的偏移量的地址,方便快速的找到A。如下图