继承允许一个类(派生类)基于另一个类(基类)创建,
派生类复用基类的属性和方法,扩展或修改基类的行为。
。。。。。。
派生类访问基类的私有成员
基类的私有成员,写set get 公开接口的话
派生类就继承这些公开接口,自然,派生类就能通过公开接口访问基类的私有成员
派生类的构造函数,初始化基类的成员属性
想要初始化,只能通过派生类的 构造函数的 列表初始化部分
但派生类构造函数的初始化列表部分,根本访问不放基类的成员属性(无论公开还是私有)
调用派生类构造函数的时候,会自动的调用基类构造函数

基类和派生类出现同名函数(同名属性)
class Base{
void show(){
cout << "基类的show" << endl;
}
};
class Derived:public Base{
void show(int a){
cout << "派生类的show" << endl;
}
};
int main(int argc,const char** argv){
Derived d;
d.show();
}
这段代码编译报错:
原因:基类的show和派生类的show没有形成重载函数(作用域相同)
函数调用不会根据具体的实参,调用不同版本的函数
d.show() 调用的是派生类的show函数
调用基类的show:
d.Base::show()
单继承
只继承一个基类。
// 基类
class Animal {
public:
void eat() {
cout << "动物在吃东西" << endl;
}
};
// 派生类
class Dog : public Animal {
public:
void bark() {
cout << "汪汪汪" << endl;
}
};
int main() {
Dog dog;
dog.eat(); // 调用基类的方法
dog.bark(); // 调用派生类的方法
return 0;
}
多继承
继承多个基类。
// 基类 1
class Animal {
public:
void eat() {
cout << "动物在吃东西" << endl;
}
};
// 基类 2
class Mammal {
public:
void breathe() {
cout << "哺乳动物在呼吸" << endl;
}
};
// 派生类
class Dog : public Animal, public Mammal {
public:
void bark() {
cout << "汪汪汪" << endl;
}
};
int main() {
Dog dog;
dog.eat(); // 调用 Animal 的方法
dog.breathe(); // 调用 Mammal 的方法
dog.bark(); // 调用 Dog 的方法
return 0;
}
多层继承
派生类作为另派生类的基类。
// 基类
class Animal {
public:
void eat() {
cout << "动物在吃东西" << endl;
}
};
// 派生类 1
class Mammal : public Animal {
public:
void breathe() {
cout << "哺乳动物在呼吸" << endl;
}
};
// 派生类 2
class Dog : public Mammal {
public:
void bark() {
cout << "汪汪汪" << endl;
}
};
int main() {
Dog dog;
dog.eat(); // 调用 Animal 的方法
dog.breathe(); // 调用 Mammal 的方法
dog.bark(); // 调用 Dog 的方法
return 0;
}
函数重写(Override)
派生类可以重写基类的虚函数,实现多态性。
优点
1. **代码复用**:派生类可以复用基类的代码,减少重复代码。
2. **可扩展性**:可以通过继承扩展基类的功能。
3. **灵活性**:通过多态性,可以实现运行时动态绑定。
练习
编写一个长方形类,
私有成员 a,b
构造函数初始化
set get 接口
编写一个正方形类,继承自长方形类
构造函数初始化
无论如何,正方形类对象总是正方形的
// 长方形类
class Rectangle {
private:
int a; // 长
int b; // 宽
public:
Rectangle(int a = 0, int b = 0) : a(a), b(b) {
cout << "Rectangle created: a = " << a << ", b = " << b << endl;
}
void setA(int a) {
this->a = a;
}
void setB(int b) {
this->b = b;
}
int getA() const {
return a;
}
int getB() const {
return b;
}
int area() const {
return a * b;
}
};
// 正方形类
class Square : public Rectangle {
public:
Square(int side = 0) : Rectangle(side, side) {
cout << "Square created: side = " << side << endl;
}
// 重写 setA,确保长和宽相等
void setA(int a) {
Rectangle::setA(a);
Rectangle::setB(a);
}
void setB(int b) {
Rectangle::setA(b);
Rectangle::setB(b);
}
};
int main() {
// 测试长方形类
Rectangle rect(3, 4);
cout << "Rectangle area: " << rect.area() << endl;
rect.setA(5);
rect.setB(6);
cout << "Modified Rectangle area: " << rect.area() << endl;
// 测试正方形类
Square square(5);
cout << "Square area: " << square.area() << endl;
square.setA(7);
cout << "Modified Square area: " << square.area() << endl;
cout << "Square sides: a = " << square.getA() << ", b = " << square.getB() << endl;
return 0;
}
封装消息队列
class Msg{
key_t key
int id;
int channel
}
实现以下功能
Msg m("文件名")
m[1].send("数据"),将数据发送到1号频道中
string str = m[1].recv(int size) 从1号频道中读取消息,并且返回把 send 改成 operator<< ,recv 改成 operator>>
实现效果:
m[1] << "helloworld" 将 "helloworld" 写入消息队列的1号频道中
m[1] >> str 读取消息队列中1频道中的消息,存入 str
class Msg {
public:
struct message {//删除消息队列
long mtype; // 类型(频道)
char mtext[1024]; // 数据
};
Msg(const string& filename) {// 创建或打开消息队列
key = ftok(filename.c_str(), 'M'); // 使用文件名生成 key
id = msgget(key, 0666 | IPC_CREAT); // 创建或打开消息队列
}
~Msg() {//删除消息队列
msgctl(id, IPC_RMID, nullptr);
}
class Channel {//一个频道
public:
Channel(int msgid, int channel) : msgid(msgid), channel(channel) {}
// 重载 << :发送消息
void operator<<(const string& data) {
message msg;
msg.mtype = channel; // 设置频道
strncpy(msg.mtext, data.c_str(), sizeof(msg.mtext)); // 拷贝数据
msgsnd(msgid, &msg, sizeof(msg.mtext), 0);
}
// 重载 >> :接收消息
void operator>>(string& data) {
message msg;
msgrcv(msgid, &msg, sizeof(msg.mtext), channel, 0) ;
data = string(msg.mtext); // 将消息数据存入字符串
}
private:
int msgid;
int channel;
};
// 重载 [] :返回指定频道的 Channel 对象
Channel operator[](int channel) {
return Channel(id, channel);
}
private:
key_t key;
int id;
};
int main() {
Msg m("msgfile");// 创建消息队列
// 发送消息到 1 号频道
m[1] << "Hello, Channel 1!";
// 从 1 号频道接收消息
string str;
m[1] >> str;
cout << "Received from Channel 1: " << str << endl;
// 发送消息到 2 号频道
m[2] << "Hello, Channel 2!";
// 从 2 号频道接收消息
m[2] >> str;
cout << "Received from Channel 2: " << str << endl;
return 0;
}
封装信号灯集
class Sem{
key_t key
int id;
int index
}
实现以下功能
Sem s(参数x,参数y):创建信号灯集,信号灯集中存在 x 个信号量,初始化为 y
s[1].init(10):手动初始化信号灯集中的第1个信号量,初始化成 10
s[1] + 1 让信号灯集中的第1个信号量的值 +1
s[1] - 1 让信号灯集中的第1个信号量的值 -1追加 operator ++ 功能,即解锁一次
以及 operator-- 功能, 即上锁一次
class Sem {
public:
// 构造函数:创建信号灯集,并初始化所有信号量为 y
Sem(int x, int y) : count(x) {
key = ftok(".", 'S'); // 使用当前目录和字符 'S' 生成 key
id = semget(key, x, 0666 | IPC_CREAT); // 创建信号灯集
// 初始化所有信号量为 y
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
arg.val = y;
for (int i = 0; i < x; i++)
semctl(id, i, SETVAL, arg);
}
// 析构函数:删除信号灯集
~Sem() {
semctl(id, 0, IPC_RMID);
}
// 内部类:表示一个信号量
class Semaphore {
public:
Semaphore(int semid, int index) : semid(semid), index(index) {}
// 手动初始化信号量
void init(int value) {
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;
arg.val = value;
semctl(semid, index, SETVAL, arg);
}
// 重载 + :信号量值加 1
void operator+(int value) {
struct sembuf op;
op.sem_num = index;
op.sem_op = value; // 增加的值
op.sem_flg = 0;
semop(semid, &op, 1) ;
}
// 重载 - :信号量值减 1
void operator-(int value) {
struct sembuf op;
op.sem_num = index;
op.sem_op = -value; // 减少的值
op.sem_flg = 0;
semop(semid, &op, 1) ;
}
// 重载 ++ :解锁一次(信号量加 1)
void operator++() {
(*this) + 1;
}
// 重载 -- :上锁一次(信号量减 1)
void operator--() {
(*this) - 1;
}
// 获取信号量的当前值
int getValue() {
return semctl(semid, index, GETVAL);
}
private:
int semid;
int index;
};
// 重载 [] :返回指定索引的信号量
Semaphore operator[](int index) {
return Semaphore(id, index);
}
private:
key_t key;
int id;
int count; // 信号量数量
};
// 测试程序
int main() {
// 创建信号灯集,包含 3 个信号量,初始化为 5
Sem s(3, 5);
// 手动初始化第 1 个信号量为 10
s[1].init(10);
cout << "Semaphore 1 value after init: " << s[1].getValue() << endl;
// 第 1 个信号量加 1
s[1] + 1;
cout << "Semaphore 1 value after +1: " << s[1].getValue() << endl;
// 第 1 个信号量减 1
s[1] - 1;
cout << "Semaphore 1 value after -1: " << s[1].getValue() << endl;
// 解锁一次(信号量加 1)
++s[1];
cout << "Semaphore 1 value after ++: " << s[1].getValue() << endl;
// 上锁一次(信号量减 1)
--s[1];
cout << "Semaphore 1 value after --: " << s[1].getValue() << endl;
return 0;
}