好友成员函数定义与类内初始值设定项

时间:2016-01-16 07:10:45

标签: c++ class c++11 friend

我最近正在阅读C++ Primer并被相同的代码in this question所困(虽然略有不同),但我的问题却有所不同。我知道有很多类似的问题,但在搜索之后,似乎没有答案可以回答我的问题。

一开始,当我没有添加好友成员函数时,代码工作正常。

/* First class */
class Screen {
public:
    using pos = std::string::size_type;
    using content_type = char;

    Screen() = default;
    Screen(pos ht, pos wd, content_type c)
        : height(ht), width(wd), contents(ht * wd, c) {}

    // Other inline functions are omited.

private:
    pos width = 0;
    pos height = 0;
    std::string contents;
};

/* Second class */
class Window_mgr {
public:
    using screen_index = std::vector<Screen>::size_type;

private:
    std::vector<Screen> screens{Screen(24, 80, ' ')};  // Use `Screen` ctor
};

然后,我想添加好友成员函数clear。我根据书中第281页附近的代码编写了两个版本的代码。第一个版本使用类内初始化程序初始化vector的{​​{1}}数据成员,而第二个版本使用构造函数初始化程序列表。

第一个版本(错误)就像本书所写的那样:

  

使成员函数成为朋友需要仔细构建我们的程序   以适应声明和定义之间的相互依赖性。在这个例子中,我们必须按如下方式订购我们的程序:

     
      
  • 首先,定义声明但不能定义Window_mgr的{​​{1}}类。必须在Window_mgr使用clear
  • 成员之前声明Screen   
  • 接下来,定义班级clear,包括Screen的朋友声明。
  •   
  • 最后,定义Screen,现在可以引用clear中的成员。
  •   
clear

第二个版本(无错误),其灵感来自this answer

Screen

请注意,为方便起见,我将所有3部分代码放在一个文件中,它们也可以分成三个不同的文件,包含正确的包含防护和包含头文件。

我理解前方声明和包含警卫,所以我不会问他们,这是我的问题。

  1. 如果我想直接使用类/* Part 1, usually Window_mgr.h */ class Screen; class Window_mgr { public: using screen_index = std::vector<Screen>::size_type; void clear(screen_index); private: std::vector<Screen> screens{Screen(24, 80, ' ')}; // Error: No ctor for `Screen` }; /* Part 2, usually Screen.h */ class Screen { friend void Window_mgr::clear(screen_index); public: using pos = std::string::size_type; using content_type = char; Screen() = default; Screen(pos ht, pos wd, content_type c) : height(ht), width(wd), contents(ht * wd, c) {} // Other inline functions are omited. private: pos width = 0; pos height = 0; std::string contents; }; /* Part 3, usually Window_mgr.cpp */ void Window_mgr::clear(screen_index i) { Screen &s = screens[i]; s.contents = std::string(s.height * s.width, ' '); } ,那么构造函数是在类/* Part 1, usually Window_mgr.h */ class Screen; class Window_mgr { public: using screen_index = std::vector<Screen>::size_type; void clear(screen_index); Window_mgr(); // Add ctor declaration private: std::vector<Screen> screens; // Remove in-class initializer }; /* Part 2, usually Screen.h */ class Screen { friend void Window_mgr::clear(screen_index); public: using pos = std::string::size_type; using content_type = char; Screen() = default; Screen(pos ht, pos wd, content_type c) : height(ht), width(wd), contents(ht * wd, c) {} // Other inline functions are omited. private: pos width = 0; pos height = 0; std::string contents; }; /* Part 3, usually Window_mgr.cpp */ Window_mgr::Window_mgr() : screens{Screen(24, 80, ' ')} {} // Add ctor definition // Because `Screen` is already a complete type, we can use its ctor now void Window_mgr::clear(screen_index i) { Screen &s = screens[i]; s.contents = std::string(s.height * s.width, ' '); } 之外定义来初始化数据成员Window_mgr的唯一方法(不是指针或参考)?

    我认为在第一个版本中不能使用类内初始值设定项,因为调用ctor时screens是不完整的类型。

  2. 为什么不完整的类型(Screen)可以用作Screen模板的参数?

  3. 可能的类似问题:

    我试图清楚但似乎有点冗长,无论如何感谢阅读和帮助:)。

0 个答案:

没有答案