【发布时间】:2016-07-09 06:31:11
【问题描述】:
我有一个非常简单的内联帮助类,称为IpAddress,它有两个运算符
#include <cstdint>
#include <string>
#include <array>
#include <iostream>
#include <sstream>
typedef uint8_t byte;
class IpAddress: public std::array<byte,4>
{
// ...
template<class S>
inline friend S& operator<<(S& left, const IpAddress& right) {
left.setBytes(right.data(), 4);
return left;
}
inline friend std::ostream& operator<< (std::ostream& left, const IpAddress& right) {
// do stuff eligible for an ostream
return left;
}
inline operator std::string() {
std::stringstream stream;
stream << *this;
return stream.str();
}
}
如您所见,还有一个运算符将地址转换为字符串。不幸的是,里面的
error: C2039: 'setBytes' : is not a member of 'std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>'
为什么编译器(在这种情况下为 MSVC)选择了错误的重载和非工作体?为什么不是“更专业”的 std::ostream 运算符?我该如何改变这种行为?谢谢!
【问题讨论】:
-
标准容器并不是真的要被继承(例如没有虚拟析构函数),而是使用composition。另一篇相关文章about composition over inheritance.
-
另外(也与您的问题无关)您的设计存在缺陷。不仅在继承方面(IPv4 地址真的是 signed 字节的数组吗?),而且您忘记处理 IPv6 地址。如果有的话,你可以有一个抽象的
IPAddress基类,然后有一个带有IPv4Address和IPv6Address的继承树。然后有一个工厂函数来检测(以某种方式)正确的类型并创建正确的地址对象并将其作为指向基类的指针返回。 -
最后是一个小问题...如果您在类定义中定义类似的成员函数,默认情况下它们是
inline,因此您不需要指定该关键字。 -
感谢您的评论。至于组成:我会相应地改变结构。它是一个 unsigned 字节数组。 IPv4 是唯一的用例。在使用来自不同编译单元的未明确声明的内联函数时,我曾经遇到过链接器抱怨多个符号定义的问题,因此我开始将所有内容都声明为内联;)
标签: c++ operator-overloading operators overloading