我最近正在阅读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部分代码放在一个文件中,它们也可以分成三个不同的文件,包含正确的包含防护和包含头文件。
我理解前方声明和包含警卫,所以我不会问他们,这是我的问题。
如果我想直接使用类/* 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
是不完整的类型。
为什么不完整的类型(Screen
)可以用作Screen
模板的参数?
可能的类似问题:
我试图清楚但似乎有点冗长,无论如何感谢阅读和帮助:)。