C++父类与子类进行交互

背景

在工作中,经常用到父类指针指向子类对象,通过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的,如果是protectedprivate,则无法通过这种方式调用。

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;
}

运行结果:

相关推荐
无己心8 小时前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u0103055276 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u0103055277 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝8 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u0103055278 天前
Java图像处理实战指南
人工智能·1024程序员节
u0103055279 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552711 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552711 天前
Java I/O核心操作实战
人工智能·1024程序员节
u01030552712 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节
u01030552713 天前
Java模块化编程实战指南
人工智能·笔记·1024程序员节