类对象作为成员

内容简介

一个类的成员可以是另一个类的对象。这样的成员称为对象成员。对象成员会影响构造和析构顺序。

用法

class Phone {
public:
    explicit Phone(std::string name) : name_(std::move(name))
    {
        std::cout << "Phone constructor\n";
    }
 
    ~Phone()
    {
        std::cout << "Phone destructor\n";
    }
 
    const std::string& name() const { return name_; }
 
private:
    std::string name_;
};
 
class Person {
public:
    Person(std::string name, std::string phone_name)
        : name_(std::move(name)), phone_(std::move(phone_name))
    {
        std::cout << "Person constructor\n";
    }
 
    ~Person()
    {
        std::cout << "Person destructor\n";
    }
 
private:
    std::string name_;
    Phone phone_;
};

构造和析构顺序

Person p("Alice", "iPhone");

构造顺序:

Phone constructor
Person constructor

析构顺序:

Person destructor
Phone destructor

规律:

  • 先构造成员对象,再执行外层类构造函数体。
  • 析构顺序和构造顺序相反。
  • 成员对象的构造顺序由成员声明顺序决定。

最佳代码实践

  • 成员对象优先在初始化列表中初始化。
  • 成员声明顺序和初始化列表顺序保持一致。
  • 对象成员用于表达“has-a”关系,例如 Person has a Phone
  • 能用组合表达关系时,不要急着用继承。

错误用法

class Person {
public:
    Person(std::string phone_name)
    {
        phone_ = Phone(phone_name);
    }
 
private:
    Phone phone_;
};

如果 Phone 没有默认构造函数,这段代码无法编译。应使用初始化列表。

注意事项

  • 类对象作为成员是 RAII 的基础:成员负责自己的资源,外层对象自然组合这些资源。
  • 相关:cpp初始化列表RAII

学习路径