接口作为成员变量类型

Java英雄角色与技能设计
package demo04;

public class Hero {
    private String name;//英雄名称
    private  Skill skill;//英雄技能

    public Hero() {
    }

    public Hero(String name, Skill skill) {
        this.name = name;
        this.skill = skill;
    }

    public void attact(){
        System.out.println("我叫"+name+"用技能攻击敌方");
        skill.use();//调用接口中的抽象方法
        System.out.println("攻击成功");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Skill getSkill() {
        return skill;
    }

    public void setSkill(Skill skill) {
        this.skill = skill;
    }
}

package demo04;

public interface Skill {
    void use();//释放技能的抽象方法
}

package demo04;

public class SkillImpl implements Skill {
    @Override
    public void use() {
        System.out.println("可以打怪");
    }
}

package demo04;

public class DemoMain {
    public static void main(String[] args) {
        //创建英雄
        Hero hero=new Hero();
        hero.setName("花花");
        SkillImpl skill=new SkillImpl();
        System.out.println(hero.getName());
        skill.use();
        System.out.println("----------");
        //设置英雄技能
//        hero.setSkill(new SkillImpl());//使用单独定义的实现类
//        hero.attact();
        //还可以使用匿名内部类
//        Skill skill1=new Skill() {
//            @Override
//            public void use() {
//                System.out.println("花式掌法");
//            }
//        };
//        hero.setSkill(skill1);
//        hero.attact();

        //进一步简化,同时使用匿名内部类和匿名对象
        hero.setSkill(new Skill() {
            @Override
            public void use() {
                System.out.println("升级了");
            }
        });
        hero.attact();


    }
}

<think>根据用户问题,用户想了解如何在C++中正确使用智能指针作为成员变量。结合提供的引用内容,我将整理相关知识并给出清晰解释。 引用[2]和[引用[4]提到了智能指针作为成员变量的用法,特别是shared_ptr和weak_ptr的应用场景。引用[1]则介绍了指向成员的指针,但用户问题主要关注智能指针,因此重点在shared_ptr和weak_ptr。 首先,智能指针作为成员变量时,需要考虑所有权问题。常见选择有: 1. unique_ptr:当独占该对象的所有权时使用。 2. shared_ptr:当多个对象共享所有权时使用。 3. weak_ptr:用于避免shared_ptr循环引用,它不增加引用计数。 下面分别说明: 一、使用unique_ptr作为成员变量: 适用于独占资源的情况。由于unique_ptr是独占的,所以不能直接复制,但可以通过移动语义转移所有权。 示例: class Device {}; class Settings { private: std::unique_ptr<Device> device; public: // 构造函数,通过移动语义获得所有权 Settings(std::unique_ptr<Device> d) : device(std::move(d)) {} // 返回原始指针(不推荐,因为可能造成悬挂指针)或者返回引用 Device* getDevice() { return device.get(); } // 或者返回引用 Device& getDeviceRef() { return *device; } }; 注意:如果返回原始指针,要确保Settings对象存在期间Device对象不会被销毁。由于unique_ptr独占所有权,所以Settings对象销毁时,Device对象也会销毁。 二、使用shared_ptr作为成员变量: 适用于多个对象共享同一个资源的情况。引用计数归零时自动释放资源。 示例: class Device {}; class Settings { private: std::shared_ptr<Device> device; public: Settings(std::shared_ptr<Device> d) : device(d) {} // 返回一个weak_ptr,避免外部使用shared_ptr导致引用计数增加,从而影响资源释放 std::weak_ptr<Device> getDevice() { return device; // 隐式转换为weak_ptr } }; 这里,getDevice返回weak_ptr,这样外部可以通过weak_ptr的lock()方法获取一个临时的shared_ptr来使用,但不会增加引用计数,避免循环引用。 三、使用weak_ptr作为成员变量: 通常不直接使用weak_ptr作为成员变量来持有资源,因为weak_ptr不拥有资源。它一般用于打破shared_ptr的循环引用。但有时也可以用于缓存等场景,但需要配合shared_ptr使用。 四、循环引用的例子及weak_ptr的解决方案: 考虑两个互相持有对方的shared_ptr: class B; class A { public: std::shared_ptr<B> b_ptr; }; class B { public: std::shared_ptr<A> a_ptr; }; 这样,当A和B互相引用时,引用计数永远不会归零,导致内存泄漏。解决方法是使用weak_ptr: class B; class A { public: std::shared_ptr<B> b_ptr; }; class B { public: std::weak_ptr<A> a_ptr; // 使用weak_ptr打破循环 }; 五、智能指针作为成员变量的初始化: 在构造函数中,建议使用初始化列表来初始化智能指针成员,这样更高效。 六、注意事项: 1. 避免在函数中返回智能指针的引用或裸指针,除非有充分的理由。返回裸指针可能导致悬挂指针(如unique_ptr情况下,如果对象被移动,则裸指针无效)。返回shared_ptr会增加引用计数,可能延长对象生命周期。通常,返回weak_ptr是较好的折中。 2. 如果需要支持拷贝,那么使用unique_ptr的需要自定义拷贝构造函数(因为unique_ptr不可拷贝),而shared_ptr可以拷贝但会增加引用计数。 3. 优先考虑使用make_shared来创建shared_ptr,因为它更高效(一次分配内存,同时存放控制块和对象)。 示例代码(使用shared_ptr和weak_ptr): #include <memory> #include <iostream> class Device { public: void doSomething() { std::cout << "Device is doing something." << std::endl; } }; class Settings { private: std::shared_ptr<Device> device; public: Settings(std::shared_ptr<Device> dev) : device(dev) {} std::weak_ptr<Device> getDevice() { return device; } }; int main() { auto device = std::make_shared<Device>(); Settings settings(device); // 使用weak_ptr获取Device std::weak_ptr<Device> weakDev = settings.getDevice(); if (auto sharedDev = weakDev.lock()) { sharedDev->doSomething(); // 安全使用 } else { std::cout << "Device has been destroyed." << std::endl; } return 0; } 总结: 根据所有权语义选择智能指针类型: - 独占所有权:unique_ptr - 共享所有权:shared_ptr - 需要避免循环引用或需要非拥有引用:weak_ptr 在作为成员变量时,注意在构造函数中初始化,并谨慎设计访问接口(如返回weak_ptr而不是shared_ptr,避免意外延长生命周期)。 以上内容参考了引用[2]和[4]。</think>### C++ 智能指针作为成员变量的使用方法 在 C++ 中使用智能指针作为成员变量时,需根据所有权语义选择合适的智能指针类型(`unique_ptr`, `shared_ptr`, `weak_ptr`),以下是详细指南: --- #### **1. 所有权模型与智能指针选择** | 场景 | 智能指针类型 | 特点 | |---------------------------|--------------|----------------------------------------------------------------------| | 独占所有权(唯一持有) | `std::unique_ptr` | 对象仅由当前拥有,不可复制(可通过移动转移所有权) | | 共享所有权(多对象共用) | `std::shared_ptr` | 多个对象共享资源,引用计数归零时自动释放 | | 非拥有引用(避免循环引用)| `std::weak_ptr` | 不增加引用计数,需通过 `lock()` 转为 `shared_ptr` 使用 | --- #### **2. 具体用法示例** ##### (1) `unique_ptr` 成员变量(独占所有权) ```cpp #include <memory> class Device { /* ... */ }; class Settings { private: std::unique_ptr<Device> device; // 独占所有权 public: // 构造函数:通过移动语义获取所有权 Settings(std::unique_ptr<Device> dev) : device(std::move(dev)) {} // 返回原始指针(谨慎使用!) Device* getDeviceRaw() { return device.get(); } // 返回引用(推荐) Device& getDevice() { return *device; } }; // 使用示例 auto dev = std::make_unique<Device>(); Settings settings(std::move(dev)); // 所有权转移 ``` ##### (2) `shared_ptr` + `weak_ptr` 成员变量(共享所有权) ```cpp #include <memory> class Device { /* ... */ }; class Settings { private: std::shared_ptr<Device> device; // 共享所有权 public: Settings(std::shared_ptr<Device> dev) : device(dev) {} // 返回 weak_ptr 避免循环引用 std::weak_ptr<Device> getDevice() { return device; } // [^2][^4] }; // 使用示例 auto sharedDev = std::make_shared<Device>(); Settings settings(sharedDev); // 通过 weak_ptr 安全访问 if (auto devPtr = settings.getDevice().lock()) { devPtr->use(); // 安全使用资源 } ``` ##### (3) 解决循环引用问题 ```cpp class Controller; // 前置声明 class Sensor { private: std::weak_ptr<Controller> controller; // 弱引用打破循环 public: void setController(std::shared_ptr<Controller> ctrl) { controller = ctrl; } }; class Controller { private: std::shared_ptr<Sensor> sensor; // 强引用 }; ``` --- #### **3. 关键注意事项** 1. **初始化**:智能指针成员应在构造函数**初始化列表**中初始化(避免未定义状态)。 2. **返回类型**: - 返回 `weak_ptr` 可避免意外延长生命周期(如示例中的 `getDevice()`)[^4]。 - 避免返回 `shared_ptr` 的裸引用(`shared_ptr&`),可能破坏封装。 3. **循环引用**: - 若两个互相持有 `shared_ptr`,会导致内存泄漏。 - 将其中一个改为 `weak_ptr` 打破循环(如 `Controller-Sensor` 示例)[^2]。 4. **性能**: - `shared_ptr` 有引用计数开销,高频场景慎用。 - 优先使用 `std::make_shared` 构造(减少内存分配次数)。 --- #### **4. 典型错误案例** ```cpp // 错误:返回 unique_ptr 的裸指针(可能悬空) class Settings { std::unique_ptr<Device> device; public: Device* getDevice() { return device.get(); } // 危险! }; // 错误:循环引用(内存泄漏) class A { std::shared_ptr<B> b_ptr; // 改为 weak_ptr 可修复 }; class B { std::shared_ptr<A> a_ptr; }; ``` > **最佳实践**:优先用 `unique_ptr` 简化所有权,需要共享时再用 `shared_ptr`,并通过 `weak_ptr` 提供外部访问接口[^2][^4]。 --- ### 相关问题 1. `shared_ptr` 和 `unique_ptr` 在作为函数参数传递时有何区别? 2. 如何为使用智能指针成员实现拷贝构造函数和赋值操作符? 3. `weak_ptr` 的 `lock()` 方法在什么情况下返回空指针?如何避免? 4. 在多线程环境下使用智能指针作为成员变量需要注意哪些线程安全问题? [^2]: C++智能指针作为成员变量。C++11为我们提供了shared_ptr、unique_ptr和weak_ptr这三种智能指针帮助我们更方便安全的使用动态内存。 [^4]: C++智能指针作为成员变量的用法。Let's say I would like to replace the pointers with smart pointers. A unique_ptr would not work because of getDevice(), right? So that's the time when I use shared_ptr and weak_ptr?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值