背景
在工作中,经常用到父类指针指向子类对象,通过virtual关键字实现多态;但当突然子类对象想向父类传数据时,一下子愣住了。重新回顾下C++基础
一、子类向父类传递数据
1. 基本调用方式
c++
class Parent
{
public:
void parentFunc()
{
std::cout << "parent func\n";
}
virtual void virtualFunc()
{
std::cout << "virtual func of parent\n";
}
};
class child :public Parent
{
public:
void callParentFunc()
{
//直接调用父类非虚函数
parentFunc();
//调用父类虚函数
virtualFunc();
//显示调用父类版本的虚函数
Parent::virtualFunc();
}
void virtualFunc() override
{
std::cout<< "child override func of parent\n";
Parent::virtualFunc();
}
};
int main()
{
Parent p;
child c;
c.callParentFunc();
std::cout << "*************************\n";
c.virtualFunc();
return 0;
}
***注意:***继承方式都统一为public,如果是其余两个,需要注意下权限问题
2. 通过构造函数传递数据
c++
class Parent
{
public:
Parent(std::string s, int v) :m_name(s), m_value(v)
{
std::cout << "construct function of Parent.\n";
}
protected:
std::string m_name;
int m_value;
};
class child :public Parent
{
public:
child(std::string s, int v, float data) //当继承时,尽量使用初始化列表方式
:Parent(s, v), m_data(data)
{
std::cout << "construct function of child.\n";
}
private:
float m_data;
};
int main()
{
child c("test", 2, 9.0f);
return 0;
}
3. 重写虚函数,回调
c++
class Parent
{
public:
void func1()
{
std::cout << "parent func1\n";
//调用子类提供的数据
std::string childData = getDataFromChild();
std::cout << "child say: " << childData << std::endl;
}
virtual std::string getDataFromChild() = 0;
protected:
std::string m_name;
int m_value;
};
class child :public Parent
{
public:
child(float t) :m_data(t)
{
}
std::string getDataFromChild()override
{
return "test2 ......";
}
private:
float m_data;
};
int main()
{
child c(9.0f);
c.func1();
return 0;
}
二、父类向子类传递数据
核心点: 在于protected权限上
1. 通过构造函数传递
c++
class Parent
{
public:
Parent(std::string s, int v) :m_name(s), m_value(v)
{
std::cout << "construct function of Parent.\n";
}
protected:
std::string m_name;
int m_value;
};
class child :public Parent
{
public:
child(const std::string& s, const int& value, const float& data)
:Parent(s, v), m_data(data)
{
std::cout << "construct function of child.\n";
}
private:
float m_data;
};
int main()
{
child c("test", 2, 9.0f);
return 0;
}
注意: 这里父类的构造函数是public的,如果是protected或private,则无法通过这种方式调用。
2. 通过保护成员变量直接访问
c++
class Parent {
protected: // 关键:protected 让子类可以访问
string sharedData;
vector<int> dataList;
public:
Parent() : sharedData("默认数据") {}
void setSharedData(const string& data) {
sharedData = data;
}
};
class Child : public Parent {
public:
void useParentData() {
// 子类直接访问父类的保护成员
cout << "使用父类数据: " << sharedData << endl;
// 修改父类数据
sharedData = "子类修改后的数据";
dataList.push_back(42);
}
void displayAllData() {
cout << "当前数据: " << sharedData << endl;
cout << "数据列表大小: " << dataList.size() << endl;
}
};
3.通过保护函数传递数据
c++
class Parent {
protected:
string processedData;
// 保护方法 - 只有子类可以调用
void processAndStoreData(const string& rawData) {
processedData = "处理后的_" + rawData;
cout << "父类处理并存储数据: " << processedData << endl;
}
string getProcessedData() const {
return processedData;
}
public:
virtual void execute() = 0; // 纯虚函数
};
class Child : public Parent {
public:
void execute() override {
// 子类调用父类的保护方法来处理数据
processAndStoreData("子类的原始数据");
// 使用父类处理后的数据
cout << "子类使用处理后的数据: " << getProcessedData() << endl;
}
};
4.通过事件/回调机制
核心点: 利用回调函数,父类在某个事件发生时(如数据接收完成),调用子类的特定方法。在工作项目中,推荐该做法
c++
#include <functional>
#include <vector>
class EventHandler {
protected:
vector<function<void(const string&)>> dataCallbacks;
public:
void registerDataCallback(function<void(const string&)> callback) {
dataCallbacks.push_back(callback);
}
void notifyDataReceived(const string& data) {
cout << "父类收到数据,通知子类..." << endl;
for (auto& callback : dataCallbacks) {
callback(data); // 调用子类注册的回调
}
}
};
class ChildComponent : public EventHandler {
public:
ChildComponent() {
// 注册回调函数,接收父类传递的数据
registerDataCallback([this](const string& data) {
this->onParentDataReceived(data);
});
}
private:
void onParentDataReceived(const string& data) {
cout << "子类收到父类数据: " << data << endl;
// 处理数据...
}
};
像一些框架有自己独特的方式,比如Qt的信号与槽机制<实质也是回调>。
三、整合
**设计下场景:**一个父类统一做资源管理,进行数据的接收与发送,子类负责特定的业务逻辑,并通过父类来发送数据
3.1、父类以及子类抽象类
c++
#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <memory>
class Child;
class Parent
{
protected:
std::vector<std::string> m_receivedData; //接收到的数据
std::vector<std::string> m_dataToSend; //要发送的数据
std::vector<Child*> m_childrenObjs; //所有子类对象
public:
virtual ~Parent() {}
void receiveData(const std::string& data); //统一接收数据
void sendData(const std::string& data); //统一发送数据
void registerChild(Child* c); //动态注册子类
void distributeToChildren(); //分发数据给子类
std::vector<std::string> getPendingData()const { return m_dataToSend; } //获取要发送的数据
};
class Child
{
protected:
Parent* m_parentObj; //父类引用,用于回调
std::string m_name;
public:
Child(const std::string& n, Parent* p)
:m_name(n), m_parentObj(p) {
}
virtual ~Child()
{
}
virtual void processData(const std::string& data) = 0;
void requestSendData(const std::string& data); //子类向父类请求发数据
std::string getName()const { return m_name; }
};
//具体实现
#include "Parent.h"
void Parent::receiveData(const std::string& data)
{
std::cout << "Parent receive data: " << data << std::endl;
this->m_receivedData.emplace_back(data);
this->distributeToChildren();
}
void Parent::sendData(const std::string& data)
{
std::cout << "Parent send data: " << data << std::endl;
this->m_dataToSend.emplace_back(data);
}
void Parent::registerChild(Child* c)
{
this->m_childrenObjs.emplace_back(c);
std::cout << "name of child: " << c->getName() << std::endl;
}
void Parent::distributeToChildren()
{
for (const auto& data : m_receivedData) {
for (auto child : m_childrenObjs) {
child->processData(data); //各个子类自己处理
}
}
m_receivedData.clear();
}
void Child::requestSendData(const std::string& data)
{
std::cout << m_name << " request to send data\n";
m_parentObj->sendData("[" + m_name + "]" + data);
}
3.2、子类具体定义
c++
#pragma once
#include "Parent.h"
class ChildA : public Child
{
public:
ChildA(Parent* p)
:Child("childA", p)
{
}
void processData(const std::string& data)override
{
std::cout << m_name << " find " << data << std::endl;
}
};
class ChildB :public Child
{
public:
ChildB(Parent* p)
:Child("childB", p){ }
void processData(const std::string& data)override
{
std::cout << m_name << " find " << data << std::endl;
}
};
3.3、具体使用
c++
#include <iostream>
#include "ChildA.h"
int main()
{
//1.创建父类
Parent p;
//2.创建各个子类
ChildA tmp1(&p);
ChildB tmp2(&p);
std::cout << "************************************\n";
//3.子类向父类注册
p.registerChild(&tmp1);
p.registerChild(&tmp2);
std::cout << "************************************\n";
//4.接收数据
p.receiveData("hello world.");
p.receiveData("test data.");
p.receiveData("cat dog.");
std::cout << "************************************\n";
//5.查看发送数据
auto pendingData = p.getPendingData();
std::cout << "size is " << pendingData.size() << std::endl;
for (const auto& data : pendingData) {
std::cout << " " << data << std::endl;
}
return 0;
}
运行结果:
