不能继承的类
1.可以把父类的构造函数私有,就可以使父类不被继承。
cpp
class NonInheritable {
private:
// 将构造函数设为私有
NonInheritable() {
std::cout << "NonInheritable 构造函数被调用" << std::cout << std::endl;
}
2.可以把类设为最后类,也可以不被继承。
cpp
class FinalClass final {
public:
FinalClass() {
std::cout << "FinalClass 构造函数被调用" << std::endl;
}
void display() {
std::cout << "这是一个最终类" << std::endl;
}
};
类的前置声明
类只会向上查找,如果在父类有需要调用子类的友元函数;
cpp
class Student;
class Person{
public:
friend void Display(const Person&P,const Student&s);
protected:
string name;
};
class Student:public Person
{
public:
friend void Display(const Person&P,const Student&s);
protected:
int _stunum;
}
void Display(const Person&P,const Student&s){
cout<<p.name<<endl;
cout<<s._stunum<<endl;
}
注意:友元关系不会继承,所以在子类也要定义友元。
父类定义了一个static静态成员
父类定义了一个static静态成员,则整个继承体系中只有一个这样的成员。无论派送出多少个子类,只有一个static的实例。
cpp
#include <iostream>
using namespace std;
// 1. 定义父类
class Base {
public:
static int m_count; // 声明静态成员
Base() { m_count++; } // 构造函数中计数+1
};
// 2. 必须在类外定义并初始化静态成员(这是C++规则)
int Base::m_count = 0;
// 3. 定义两个子类
class DerivedA : public Base {
// DerivedA 继承自 Base,它没有自己的 m_count,使用的是 Base::m_count
};
class DerivedB : public Base {
// DerivedB 也继承自 Base,使用的也是 Base::m_count
};
int main() {
cout << "初始状态 count: " << Base::m_count << endl; // 输出: 0
// --- 通过父类创建对象 ---
Base b1;
cout << "创建 Base b1 后:" << endl;
cout << "Base::m_count: " << Base::m_count << endl; // 1
cout << "DerivedA::m_count: " << DerivedA::m_count << endl; // 1 (共享)
cout << "DerivedB::m_count: " << DerivedB::m_count << endl; // 1 (共享)
// --- 通过子类A创建对象 ---
DerivedA a1, a2;
cout << "\n创建 DerivedA a1, a2 后:" << endl;
cout << "Base::m_count: " << Base::m_count << endl; // 3 (b1+a1+a2)
cout << "DerivedA::m_count: " << DerivedA::m_count << endl; // 3
// --- 通过子类B创建对象 ---
DerivedB b2;
cout << "\n创建 DerivedB b2 后:" << endl;
cout << "Base::m_count: " << Base::m_count << endl; // 4
cout << "DerivedB::m_count: " << DerivedB::m_count << endl; // 4
// --- 验证只有一个实例 ---
// 我们通过子类名字直接修改它
DerivedA::m_count = 100;
cout << "\n通过 DerivedA::m_count = 100 修改后:" << endl;
cout << "Base::m_count: " << Base::m_count << endl; // 变成了 100
cout << "DerivedB::m_count: " << DerivedB::m_count << endl; // 也变成了 100
return 0;
}
继承中的作用域
1在继承体系在父类和子类都有独立的作用域。
2 子类和父类有同名变量,子类会屏蔽掉父类对同名变量的访问,叫隐藏。
(可以使用 父类::父类成员 显示访问)
3,如果是同名函数的隐藏,只需要函数名相同就行。
多继承和菱形继承
每个类只有一个直接父亲时叫单继承;有两个及以上的直接父类时叫多继承。
特殊的有菱形继承
cpp
Class A
/ \
Class B Class C
\ /
Class D
cpp
// 1. 顶层父类(基类)
class Person {
public:
string m_name = "Person";
};
// 2. 两个中间子类
class Student : public Person {
// 继承了一份 m_name
};
class Teacher : public Person {
// 继承了另一份 m_name
};
// 3. 菱形底部的类(多继承)
class Assistant : public Student, public Teacher {
// 此时 Assistant 内部有两份 Person 的数据!
};
// 错误!编译器报错:对 'm_name' 的访问不明确
// cout << assistant.m_name << endl;
// 必须显式指定作用域才能访问
assistant.Student::m_name = "小明";
assistant.Teacher::m_name = "老王";
c++中引入虚继承
要加上 virtual关键字,必须两个都加virtual关键字。
cpp
class Person {
public:
string m_name = "Default";
};
// 关键点:使用 virtual 继承
class Student : virtual public Person {
};
class Teacher : virtual public Person {
};
class Assistant : public Student, public Teacher {
};
// 现在可以直接访问了,没有二义性
assistant.m_name = "Super Assistant";
cout << assistant.m_name << endl; // 输出: Super Assistant
// 无论通过哪条路径访问,指向的都是同一块内存
assistant.Student::m_name = "Modified via Student";
cout << assistant.Teacher::m_name << endl; // 输出: Modified via Student
在那个类冗余和二义性,继承时加virtual
cpp
Class A (最顶层基类)
/ \
Class B(加v) Class C(加v)
| |
Class F |
\ |
Class G (最底层)
虚继承的弊端
cpp
#include <iostream>
using namespace std;
class A {
public:
A(int val) : m_val(val) { cout << "A constructed with " << val << endl; }
int m_val;
};
class B : virtual public A {
public:
// 这里的 A(2) 在单独创建 B 对象时会执行
// 但在 D 对象中,这个调用会被忽略!
B() : A(2) { cout << "B constructed" << endl; }
};
class C : virtual public A {
public:
// 同理,这里的 A(3) 在 D 对象中也会被忽略
C() : A(3) { cout << "C constructed" << endl; }
};
class D : public B, public C {
public:
// 必须在这里显式调用 A 的构造函数!
// 如果漏掉 A(1),编译器会尝试调用 A 的默认构造函数(如果存在)
D() : A(1), B(), C() { cout << "D constructed" << endl; }
};
int main() {
D d;
// 输出顺序证明 A 是由 D 初始化的:
// A constructed with 1
// B constructed
// C constructed
// D constructed
cout << "d.m_val = " << d.m_val << endl; // 输出 1
return 0;
}
继承中的指针
cpp
class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
先继承1,再继承2。
int main()
{
Derive d;
Base1* p1 = &d;
Base2* p2 = &d;
Derive* p3 = &d;对着先继承的
return 0;
}
p1 == p3 != p2
继承和组合
cpp
继承
// 父类:动物
class Animal {
public:
void eat() {
cout << "动物正在吃东西..." << endl;
}
};
// 子类:狗 (继承自 Animal)
// 关系:狗 IS-A 动物
class Dog : public Animal {
public:
void bark() {
cout << "汪汪叫!" << endl;
}
};
/////////////////////////////////////
组合
class Engine {
public:
void start() {
cout << "引擎启动了 (轰隆隆...)" << endl;
}
};
// 容器类:汽车
// 关系:汽车 HAS-A 引擎
class Car {
private:
Engine _engine; // 组合:Car 拥有一个 Engine 对象
string _brand;
public:
Car(string brand) : _brand(brand) {}
void startCar() {
cout << _brand << " 准备启动..." << endl;
// 调用成员对象的方法
_engine.start();
cout << "汽车启动完成!" << endl;
}
};
继承是白箱复用,组合是黑箱复用。
白箱意味着,了解父类的实现,从代码逻辑去测试;
黑箱,不了解实现,从功能的角度测试;
耦合度:是模块之间"粘连"的紧密程度。它直接决定了代码修改时的风险大小------耦合度越高,牵一发而动全身的风险就越大;耦合度越低,模块就越独立。
高内聚:相关的功能聚在一起;
高内聚,低耦合是是软件工程的黄金法则。