佛山 网站建设 骏域,在哪里做网站比较好,怎样在网站上做有效的广告投放,wordpress 论坛系统目录
一、派生类的默认成员函数
二、继承与友元
三、继承与静态成员
四、复杂的菱形继承及菱形虚拟继承
五、继承和组合 一、派生类的默认成员函数 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认构造函数#xff0c;那么必须在派生…目录
一、派生类的默认成员函数
二、继承与友元
三、继承与静态成员
四、复杂的菱形继承及菱形虚拟继承
五、继承和组合 一、派生类的默认成员函数 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认构造函数那么必须在派生类的构造函数的初始化列表中显示调用基类的构造函数。 派生类的拷贝构造函数必须调用基类的拷贝构造函数完成基类的那一部分成员的拷贝初始化。 派生类的 operator 必须调用基类的 operator 完成基类的那一部分成员的赋值。 派生类的析构函数在被调用完后会自动调用基类的析构函数清理基类的那一部分成员即在派生类的析构函数中不用显示地调用基类的析构函数。 在创建派生类对象时先调用基类的构造函数再调用派生类的构造函数。 在销毁派生类对象时先调用派生类的析构函数再调用基类的析构函数。
#include iostream
using namespace std;
class Person
{
public:Person(const char* name 张三, int age 18): _name(name), _age(age){cout Person::default constructor 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;_age p._age;}return *this;}
~Person(){cout ~Person() endl;}
protected:string _name; // 姓名int _age; // 年龄
};
class Student : public Person
{
public:Student(const char* name 张三, int age 18, int stu_id 0): Person(name, age), _stu_id(stu_id){cout Student::default constructor endl;}
Student(const Student s): Person(s), _stu_id(s._stu_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); // operator(s); 会陷入死循环_stu_id s._stu_id;}return *this;}
~Student(){cout ~Student() endl;}
protected:int _stu_id; // 学号
};
int main()
{Student s1(李四, 20, 1);// Person::default constructor// Student::default constructor
Student s2(s1);// Person(const Person p)// Student(const Student s)
Student s3;// Person::default constructor// Student::default constructor
s3 s1;// Student operator(const Student s)// Person operator(const Person p)
// ~Student()// ~Person()// ~Student()// ~Person()// ~Student()// ~Person()return 0;
} 二、继承与友元
友元关系不能继承即基类友元不能访问子类私有和保护成员。
#include iostream
using namespace std;
class Student;
class Person
{friend void Print(const Person p, const Student s);
protected:string _name 张三;int _age 18;
};
class Student : public Person
{// 必须声明否则会报错friend void Print(const Person p, const Student s);
protected:int _stu_id 0;
};
void Print(const Person p, const Student s)
{cout p._name p._age endl;cout s._stu_id endl;
}
int main()
{Person p;Student s;Print(p, s);return 0;
} 三、继承与静态成员
如果基类定义了 static 静态成员无论派生出了多少个类在整个继承体系中都只有一个 static 静态成员实例。
#include iostream
using namespace std;
class Person
{
public:Person() { _count; }
protected:string _name;int _age;
public:static int _count; // static 静态成员变量
};
int Person::_count 0;
class Student : public Person
{
protected:int _stu_id;
};
class Graduate : public Student
{
protected:string _seminarCourse; // 研究科目
};
int main()
{cout Person::_count Student::_count Graduate::_count endl;// 输出的三个地址相同Person p1;Student s1;Student s2;Graduate g1;Graduate g2;Graduate g3;cout Person::_count endl; // 6return 0;
} 四、复杂的菱形继承及菱形虚拟继承
单继承一个派生类只有一个直接基类时称这种继承关系为单继承。
多继承一个派生类有两个或两个以上直接基类时称这种继承关系为多继承。
菱形继承是多继承的一种特殊情况它会造成数据冗余和二义性的问题例如
#include iostream
using namespace std;
// 间接基类 A
class A
{
public:int _a;
};
// 直接基类 B
class B : public A
{
public:int _b;
};
// 直接基类 C
class C : public A
{
public:int _c;
};
// 派生类 D
class D : public B, public C
{
public:int _d;
};
int main()
{D d;// 为了消除歧义必须在 _a 前面指明它具体来自哪个类d.B::_a 0;d.C::_a 1;d._b 2;d._c 3;d._d 4;return 0;
} 为了解决菱形继承中的问题C 提出了虚继承使得在派生类中只保留一份间接基类的成员。
在继承方式前面加上 virtual 关键字就是虚继承例如
#include iostream
using namespace std;
// 间接基类 A
class A
{
public:int _a;
};
// 直接基类 B
class B : virtual public A // 虚继承
{
public:int _b;
};
// 直接基类 C
class C : virtual public A // 虚继承
{
public:int _c;
};
// 派生类 D
class D : public B, public C
{
public:int _d;
};
int main()
{D d;d._a 1; // okd._b 2;d._c 3;d._d 4;return 0;
} 虚继承底层实现原理与编译器相关一般是通过虚基类指针和虚基类类表实现的。 每个虚继承的子类都有一个虚基类指针该指针指向一个虚基类表表中记录了虚基类和本类的偏移量通过这个偏移量就可以找到虚基类成员。 当虚继承的子类被当作父类继承时虚基类指针也会被继承。 五、继承和组合
面向对象系统中功能复用的两种最常用技术是类继承和对象组合object composition。
类继承允许你根据基类的实现定义派生类的实现这种通过生成派生类的复用通常被称为白箱复用white-box reuse。术语 白箱 是相对可视性而言的在继承方式中基类的内部细节对派生类可见。继承一定程度上破坏了基类的封装基类的改变对派生类有很大的影响。派生类和基类的依赖关系很强耦合度高。
对象组合是类继承之外的另一种复用选择新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用white-box reuse因为对象的内部细节是不可见的对象只能以 黑箱 的形式出现。组合类之间没有很强的依赖关系耦合度低。
因此在实际中尽量多使用组合。不过继承也有用武之地的public 继承是一种 is-a 的关系即每个派生类对象都是一个基类对象组合是一种 has-a 的关系即假设 B 组合了 A那么每个 B 类对象都有一个 A 类对象而有些关系就适合用继承另外要实现多态也必须要用继承。
例一
class Car
{
protected:string _color; // 颜色string _num; // 车牌号
};
class AITO : public Car
{
public:void Describe() const { cout Intelligent endl; }
};
class AVATR : public Car
{
public:void Describe() const { cout luxurious endl; }
}; AITO、AVATR 和 Car 构成 is-a 的关系。 例二
class Tire
{
protected:string _brand; // 品牌size_t _size; // 尺寸
};
class Car
{
protected:string _color;string _num;Tire _t;
}; Car 和 Tire 构成 has-a 的关系。