当前位置:  开发笔记 > 编程语言 > 正文

重载运算符<< - C++

如何解决《重载运算符<<-C++》经验,为你挑选了1个好方法。

背景

我有一个容器类,它在内部使用vector .我已经为这个包装类提供了一个方法AddChar(std :: string),它对内部向量执行push_back().在我的代码中,我必须在容器中添加多个项目.为此,我必须使用

container.AddChar("First");
container.AddChar("Second");

这使代码更大.因此,为了使它更容易,我计划重载operator <<.这样我就可以写了

container << "First" << "Second"

并且两个项目将被添加到底层矢量.

这是我用于此的代码

class ExtendedVector
{
private:
    vector container;

public:
    friend ExtendedVector& operator<<(ExtendedVector& cont,const std::string str){
        cont.AddChar(str);
        return cont;
    }

    void AddChar(const std::string str)
    {
        container.push_back(str);
    }

    string ToString()
    {
        string output;
        vector::iterator it = container.begin();
        while(it != container.end())
        {
            output += *it;
            ++it;
        }
        return output;
    }
};

它按预期工作.

问题

    操作员过载是否正确写入?

    在这样的情况下重载运算符是一种好习惯吗?

    此代码是否存在任何性能问题或任何其他问题?

有什么想法吗?

编辑

在听到优秀的评论之后,我决定不要超载<<因为它在这里没有意义.我删除了运算符重载代码,这是最终代码.

class ExtendedVector
{
private:
    vector container;

public:

    ExtendedVector& AddChar(const std::string str)
    {
        container.push_back(str);
        return *this;
    }

         .. other methods
}

这允许我添加

container.AddChar("First").AddChar("Second")

在C#中,我可以使用params关键字更轻松地完成此操作.代码就像

void AddChar(params string[] str)
{
    foreach(string s in str)
       // add to the underlying collection
}

我知道在C++中,我们可以使用...来指定参数的变量长度.但是AFAIK,它不是类型安全的.这样做是推荐的做法吗?这样我就可以写了

container.AddChar("First","Second")

谢谢你的回复.



1> Johannes Sch..:

操作员过载是否正确写入?

它是,但人们可以做得更好.与其他人提到的一样,您的功能可以完全由现有的公共功能定义.为什么不让它只使用那些?现在,它是一个朋友,这意味着它属于实现细节.如果将operator <<作为成员添加到您的类中,情况也是如此.但是,使您的运算符<< 非成员,非朋友功能.

class ExtendedVector {
    ...
};

// note, now it is *entirely decoupled* from any private members!
ExtendedVector& operator<<(ExtendedVector& cont, const std::string& str){
    cont.AddChar(str);
    return cont;
}

如果你改变了你的课程,你将无法确定你的操作员<<仍然可以工作.但是,如果您的运算符<<完全仅依赖于公共函数,那么您可以确保它仅在对您的类的实现细节进行更改后才能工作.好极了!

在这样的情况下重载运算符是一种好习惯吗?

正如另一个人再次说的那样,这是有争议的.在许多情况下,操作员超载一见钟情看起来很"整洁",但明年看起来会像地狱一样,因为在给出一些符号特别的爱时,你不再知道你的想法了.在运算符<<的情况下,我认为这是一个好用.它用作流的插入操作符是众所周知的.我知道Qt和KDE应用程序在类似的情况下广泛使用它

QStringList items; 
items << "item1" << "item2";

类似的情况boost.format也重operator%用于在其字符串中传递占位符的参数:

format("hello %1%, i'm %2% y'old") % "benny" % 21

在那里使用它当然也是有争议的.但它用于printf格式指定是众所周知的,所以它的使用也是可以的,imho.但一如既往,风格也是主观的,所以带上一粒盐:)

我如何以类型安全的方式接受变长参数?

好吧,如果你正在寻找同质论证,有接受向量的方法:

void AddChars(std::vector const& v) {
    std::vector::const_iterator cit =
        v.begin();
    for(;cit != v.begin(); ++cit) {
        AddChar(*cit);
    }
}

传递它并不是很舒服.你必须手动构建你的矢量然后传递...我看到你已经对vararg风格函数有了正确的感觉.不应该将它们用于这种代码,只有在与C代码接口或调试函数时才使用它们.处理这种情况的另一种方法是应用预处理器编程.这是一个高级主题,非常黑客.我们的想法是自动生成一个大小超过某个上限的重载,如下所示:

#define GEN_OVERLOAD(X) \
void AddChars(GEN_ARGS(X, std::string arg)) { \
    /* now access arg0 ... arg(X-1) */ \
    /* AddChar(arg0); ... AddChar(arg(N-1)); */ \
    GEN_PRINT_ARG1(X, AddChar, arg) \
}

/* call macro with 0, 1, ..., 9 as argument
GEN_PRINT(10, GEN_OVERLOAD)

那是伪代码.您可以在这里查看boost预处理器库.

下一个C++版本将提供更好的可能性.可以使用初始化列表:

void AddChars(initializer_list ilist) {
    // range based for loop
    for(std::string const& s : ilist) {
        AddChar(s);
    }
}

...
AddChars({"hello", "you", "this is fun"});

在下一个C++中,也可以使用可变参数模板支持任意多个(混合类型)参数.GCC4.4将为他们提供支持.GCC 4.3已经部分支持它们.

推荐阅读
sx-March23
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有