网站推广建设加盟企业网站的特征
2026/1/17 5:40:12 网站建设 项目流程
网站推广建设加盟,企业网站的特征,电商的网站,网站域名包括一. 友元#xff1a;“朋友的朋友不是我的朋友”——友元关系不可继承 在C中#xff0c;基类的友元函数/类无法直接访问派生类的私有成员。这就像你父亲的朋友#xff0c;不等于你的朋友#xff0c;友元关系不具有继承性。如果需要让友元访问派生类成员#…一. 友元“朋友的朋友不是我的朋友”——友元关系不可继承在C中基类的友元函数/类无法直接访问派生类的私有成员。这就像你父亲的朋友不等于你的朋友友元关系不具有继承性。如果需要让友元访问派生类成员必须在派生类中重新声明一下友元。具体示例// 前置声明告诉编译器Student类存在 class Student; class Person { //友元函数不能被子类继承 friend void Display(const Person p, const Student s); public: protected: string _name张三;//姓名 }; class Student :public Person { //在子类里面也声明一下 friend void Display(const Person p, const Student s); protected: int _stuNum1301984;//学号 }; void Display(const Person p, const Student s) { cout p._name endl;//访问基类成员 cout s._stuNum endl;//访问派生类成员 } int main() { Person p; Student s; // 编译报错error C2248: “Student::_stuNum”: 无法访问 protected 成员 // 解决方案Display也变成Student 的友元即可 Display(p, s); return 0; }核心结论基类友元仅能访问基类的 private/protected 成员若需访问派生类成员必须在派生类中重新声明友元友元关系是一对一的不能继承自动传递。二. 静态成员“全家共用一份”——继承体系中静态成员的共享性基类的静态成员静态变量/静态函数在整个继承体系中仅存在一份派生类和基类共享该成员不会因为继承而产生多个。这与非静态成员不同 —— 非静态成员每个对象一份。class Person { public: string _name; static int _count; }; int Person::_count 0; class Student :public Person { protected: int _stuNum; }; int main() { Person p; Student s; // 这里的运行结果可以看到非静态成员_name的地址是不一样的 // 说明派生类继承下来了基类派生类对象各有一份 cout p._name endl; cout s._name endl; cout endl; // 这里的运行结果可以看到静态成员_count的地址是一样的 // 说明派生类和基类共用同一份静态成员 cout p._count endl; cout s._count endl; cout endl; // 公有的情况下基类派生类指定类域都可以访问静态成员 cout Person::_count endl; cout Student::_count endl; cout endl; return 0; }核心结论前两个前面讲过静态成员变量必须在类外初始化否则会触发链接错误静态成员函数只能访问静态成员变量无法访问非静态成员继承体系中所有类基类派生类共享同一份静态成员修改一处会影响全局。三. 多继承及菱形继承问题本质特点与解决方案3.1 单继承与多继承模型单继承一个派生类只有⼀个直接基类时称这个继承关系为单继承多继承一个派生类有两个或以上直接基类时称这个继承关系为多继承多继承对象在内存中的模型是先继承的基类在前面后继承的基类在后面派生类成员在放到最后面。3.2 菱形继承虚继承解决“数据冗余”与“二义性”菱形继承是指“一个派生类同时继承两个基类而这两个基类又共同继承自一个顶层基类”的结构(并非一定是个菱形结构的图)。这种结构会导致两个核心问题数据冗余顶层基类的成员被继承两次二义性访问成员时无法确定到底属于那个基类3.2.1 菱形继承的坑(未完全解决时)// 顶层基类 class Person { public: string _name; // 会被继承两次 }; // 中间基类1 class Student : public Person {}; // 中间基类2 class Teacher : public Person {}; // 最终派生类菱形继承 class Assistant : public Student, public Teacher {}; int main() { Assistant a; // a._name 张三; // 编译报错二义性到底是Student::_name还是Teacher::_name呢 // 只能显式指定但数据冗余仍存在没有解决 a.Student::_name 李四; a.Teacher::_name 王五; cout a.Student::_name endl; // 输出李四 cout a.Teacher::_name endl; // 输出王五 return 0; }3.2.2 虚继承彻底解决菱形继承问题//顶层基类 class Person { public: Person(const char* name) :_name(name) {} public: string _name; // 姓名 /*int _age; int _tel; string _address;*/ }; // 中间基类1虚继承Person添加virtual //virtual谁导致的就在继承谁时加 class Student : virtual public Person { public: Student(const char* name, int num) :Person(name)// 虚继承下中间基类暂时不初始化顶层基类 , _num(num) {} protected: int _num; //学号 }; // 中间基2虚继承Person添加virtual //virtual谁导致的就在继承谁时加 class Teacher : virtual public Person { public: Teacher(const char* name, int id) :Person(name)// 虚继承下中间基类暂时不初始化顶层基类 , _id(id) {} protected: int _id; // 职工编号 }; // 最终派生类菱形继承Person成员仅一份 class Assistant : public Student, public Teacher { public: // 关键虚继承下顶层基类的构造由最终派生类显式调用 Assistant(const char* name1, const char* name2, const char* name3) :Person(name1)// 直接初始化顶层基类 ,Student(name2, 1) ,Teacher(name3, 2) , _majorCourse(计算机) {} protected: string _majorCourse; // 主修课程 }; int main() { // 思考一下这里a对象中_name是张三, 李四, 王五中的哪一个 Assistant a(张三, 李四, 王五); //上面有三次Person(name)但其实就只有在Assistant里一次其它两次会跳过。 //所以是张三 return 0; }虚继承的关键细节virtual仅需添加在中间基类继承顶层基类时最终派生类继承中间基类时不需要添加。虚继承下顶层基类的构造函数由最终派生类负责调用中间基类的构造函数不再初始化顶层基类(但还是需要写出来的)。虚继承时会增加底层复杂度(虚基表)因此尽量避免设计菱形继承结构除非业务逻辑必须如此。友元静态成员菱形继承总结表场景核心特性避坑避坑指南友元友元关系不随继承传递若需访问派生类私有成员必须在派生类中重新声明友元控制友元使用范围避免因过度开放访问破坏类的封装性静态成员全继承体系共享唯一实例需在类外初始化静态函数仅能访问静态成员变量关注静态成员的“全局共享”特性多线程场景需加锁保护避免并发冲突菱形继承因间接继承共同基类导致数据冗余和访问二义性需通过虚继承解决虚继承下顶层基类由最终派生类初始化设计阶段优先规避菱形结构确需使用时再通过虚继承处理避免过度依赖增加代码复杂度3.2.3 多继承中指针偏移问题下面说法正确的是(C)Ap1 p2 p3 Bp1 p2 p3 Cp1 p3 ! p2 Dp1 ! p2 ! p3class Base1 { public: int _b1; }; class Base2 { public: int _b2; }; class Derive : public Base1, public Base2 { public: int _d; }; int main() { Derive d; Base1* p1 d; Base2* p2 d; Derive* p3 d; return 0; }3.3 IO库中的菱形虚拟继承templateclass CharT, class Traits std::char_traitsCharT class basic_ostream : virtual public std::basic_iosCharT, Traits {}; templateclass CharT, class Traits std::char_traitsCharT class basic_istream : virtual public std::basic_iosCharT, Traits {};四. 继承与组合C 代码复用的核心方式对比继承is-a 关系体现 “子类是父类的一种” 的逻辑例如 “Student 是 Person 的一种”“BMW 是 Car 的一种”。派生类直接继承基类的成员属性 / 方法可扩展自身独有功能属于 “白箱复用”—— 子类能访问基类非私有成员了解其内部实现细节。组合has-a 关系体现 “一个类包含另一个类的对象” 的逻辑例如 “Car 包含 Tire”“Computer 包含 CPU”。组合类通过调用被包含对象的公开接口实现复用被包含类的内部细节对组合类隐藏属于 “黑箱复用”。// Tire(轮胎)和Car(⻋)更符合has-a的关系 class Tire { protected: string _brand Michelin; // 品牌 size_t _size 17; // 尺⼨ }; class Car { protected: string _colour 白色; // 颜色 string _num 陕ABIT00; // ⻋牌号 Tire _t1; // 轮胎 Tire _t2; // 轮胎 Tire _t3; // 轮胎 Tire _t4; // 轮胎 }; // Car和BMW/Benz更符合is-a的关系 class BMW : public Car { public: void Drive() { cout 好开-操控 endl; } }; class Benz : public Car { public: void Drive() { cout 好坐-舒适 endl; } }; // stack和vector的关系既符合is-a也符合has-a templateclass T class vector {}; // 继承is-a,白盒耦合度高 templateclass T class stack :public vectorT {}; //组合 has-a黑盒耦合度低 templateclass T class stack { vectorT _v; };选择原则优先使用组合组合的低耦合特性更符合“高内聚、低耦合”的设计原则代码可维护性更强尤其在复杂系统中能减少类间依赖带来的修改风险。必要时使用继承当类间明确存在 “is-a” 关系或需要通过继承实现多态如基类指针指向派生类对象时选择继承避免为了复用少量代码而强行使用继承导致耦合度升高。维度继承is-a组合has-a封装性较差派生类可直接访问基类的protected成员暴露基类内部细节破坏封装边界较好被组合类的私有成员完全隐藏组合类仅通过接口调用符合封装原则灵活性低继承关系是编译期确定的静态关系运行时无法动态变更父类或替换继承逻辑高被组合对象可在运行时动态替换如依赖注入能灵活适配不同场景需求适用场景1. 类间存在明确的“is-a”层级关系如“苹果是水果”“轿车是汽车”2. 需要利用继承实现多态基类指针/引用指向派生类对象1. 类间是“包含”关系如“汽车包含轮胎”“电脑包含CPU”2. 追求低耦合设计需降低类间依赖以提升可维护性3. 需要动态替换功能模块如不同品牌的轮胎可替换耦合度高基类的接口或实现修改会直接传导至派生类影响范围广低被组合类仅通过公开接口与组合类交互其内部实现修改不影响组合类

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询