跟我学C++高级篇——名称反射创建对象的一种实现的说明

240 篇文章 100 订阅

一、具体情况

在前面的文章“名称反射创建对象的一种实现”发布后,有同学问为什么在实例中既给了模板的名称,又给了字符串名称,这还有什么意义呢?这个问题非常好,当时一时偷懒,没有把事情说清楚,这篇文章算是对提问同学的一个回答。
其实很简单,如果把实现的类名和声明的类型换成不同的类,同时这个需要反射的类必须继承前面提到的ClassInstance,再在给定的类(即Worker)中实现一个创建,那么整个反射的过程就符合了一般反射的习惯。

二、补充例程

基于上面的分析,看下面的代码分析即可明白:

......

//测试类
class Worker {
public:
    Worker() {}
    Worker(int a, int b) : a_(a), b_(b) {}

public:
    void display() { std::cout << "-this is Worker display function!--:" << a_ + b_ << std::endl; }

private:
    int a_ = 0;
    int b_ = 0;
};

class Worker1 {
public:
    Worker1() {}
    Worker1(int a) {}

public:
    void display1() { std::cout << "--this is worker1 display1 function--" << std::endl; }
};

int main() {
    //重点看这里的声明和后面的获取,即下面的两行代码
    ClassInstance<Worker, int, int> dc;
    auto* pp = InstanceFactory<Worker, int, int>::Instance()->CreateInstance("Worker", 1, 2);

    pp->display();

    return 0;
}

上面就上次发的代码的问题提出部分,这次完善一下代码:

//实例模板
template <typename T, typename... Args>
class ClassInstance {
public:
    struct RegContain {
        RegContain() {
            char* sName = nullptr;
            std::string className;

            //注意:这是Linux平台,其它平台需要处理相关类名
           // sName = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);
            sName = name;
            if (nullptr != sName) {
                //className = sName;
                //free(sName);
            }

             className = name;
            InstanceFactory<T, Args...>::Instance()->RegClass(className, CreateObject);
        }
        inline void done() const {};
    };

public:

    ClassInstance() {
        //this->InstanceFromName();
        reg_.done(); // 确保调用前模板实例化,请参看前面的模板延迟加载
    }
    ~ClassInstance() {};
public:
    // 变参创建实例
    static T* CreateObject(Args &&...args) {
        T* pIns = nullptr;
        try {
            pIns = new T(std::forward<Args>(args)...);
        }
        catch (...) {
            return nullptr;
        }
        return pIns;
    }

private:
    static RegContain reg_;
};

template <typename T, typename... Args>
typename ClassInstance<T, Args...>::RegContain ClassInstance<T, Args...>::reg_;
//测试类
class Worker :public ClassInstance<Worker,int,int> {
public:
    Worker() {}
    Worker(int a, int b) : a_(a), b_(b) {}

public:

    void display() { std::cout << "-this is Worker display function!--:" << a_ + b_ << std::endl; }

private:
    int a_ = 0;
    int b_ = 0;
};
class ObjIns {
public:
    template<typename ...Targs>
    Worker* GetObj(const std::string& name, Targs&&... args)
    {
        Worker* p = InstanceFactory<Worker,Targs...>::Instance()->CreateInstance(name, std::forward<Targs>(args)...);
        return p;
    }
};
int main() {
    ObjIns o;
    auto *pp = o.GetObj("Worker",3,6);

    pp->display();
}

这里的代码主要修改了两处,一处是将实例代码的生成InstanceFactory从函数转到了内部类,确保模板在调用函数前的实例化(当然也可以使用其它的方式);另外一个就是将实例的应用封装了一层,即原来的Worker不直接暴露,而是通过一个对象类ObjIns来动态创建,这样就更符合开发者对反射使用的要求。
有的同学可能会问,这个还是有问题啊,每次都得创建一个新类的构建函数来实现啊,同学可以想一想,是不是在某种场景下,可以使用继承?或者干脆把功能从Worker中单独提取出去?再使用继承!自己可以试试,网上很多的代码其实也是这个思路。

三、总结

这个怪偷懒的精神做祟,说明一下就好了。这也说明,对细节的说明一定要清晰严谨,不能想当然的别人也会这么理解。沟通的成本,就是这样产生的。谢谢热心同学“ω劉εз珩”的指出,非常感谢,共同进步。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值