【问题标题】:Is there anything like C++ default object method有没有类似 C++ 默认对象方法的东西
【发布时间】:2021-11-01 22:54:30
【问题描述】:

我有以下模板合并排序程序:

#include <iostream>
#include <vector>
#include <string>

// trying to create a default method call
class CInstance {
private:
    std::string str_;
public:
    CInstance(const std::string& str) : str_(str) {}
    bool const  operator>(const CInstance& that){  return (this->str_.size() > that.str_.size());}
};

template<class T>
class CObj {
private:
    T val;
public:
    CObj(const T n) : val(n) {}
    T Get() { return val; }
};

template<class T>
using vcobj = std::vector<CObj<T>>;

template<class T>
void display(vcobj<T>& v) {
    for (auto &i : v) {
        std::cout << i.Get() << " ";
    }
    std::cout << "\n";
}

template<class T>
vcobj<T> Merge(vcobj<T>& lv, vcobj<T>& rv) {
    vcobj<T> ret;
    
    auto lsize = lv.size();
    auto rsize = rv.size();
    unsigned int lpin = 0, 
                 rpin = 0;
                 
    while(lpin < lsize &&  rpin < rsize) {
        if(lv.at(lpin).Get() > rv.at(rpin).Get()) {
            ret.emplace_back(rv.at(rpin).Get());
            rpin++;
        }
        else {
            ret.emplace_back(lv.at(lpin).Get());
            lpin++;
        }
    }
    
    for (auto i=lpin; i<lsize; i++) {
        ret.emplace_back(lv.at(i).Get());
    }
    
    for (auto i=rpin; i<rsize; i++) {
        ret.emplace_back(rv.at(i).Get());
    }
    
    return ret;
}

template<class T>
vcobj<T> Sort(const vcobj<T>& v) {
    vcobj<T> ret;
    
    auto size = v.size();
    if(size == 0) {
        return ret;
    }
    if(size > 1) {
        
        auto mid = size / 2;
        
        vcobj<T> l(v.begin(), v.begin()+mid);
        auto lv = Sort(l);
        
        vcobj<T> r(v.begin()+mid, v.end());
        auto rv = Sort(r);
        
        ret = Merge(lv, rv);
        
    }
    else {
        ret = v;
    }
    
    return ret;
}

int main() {
    {
        vcobj<int> v = {4, 5, 2, 1, 9, 6, 10, 8, 15, 3, 7};
        display(v);
        auto sorted = Sort(v);
        display(sorted);
    }
    
    {
        vcobj<float> v = {0.01, 0.001, 0.002, 0.009, 0.010, 0.0003, 0.00001};
        display(v);
        auto sorted = Sort(v);
        display(sorted);
    }
    
    {
        vcobj<std::string> v = {{"pineapple"}, {"jackfruit"}, {"mango"}, {"apple"}, {"banana"}};
        display(v);
        auto sorted = Sort(v);
        display(sorted);
    }
    
    // causing problem
    {
        vcobj<CInstance> v = {{"pineapple"}, {"jackfruit"}, {"mango"}, {"apple"}, {"banana"}};
        display(v);
        auto sorted = Sort(v);
        display(sorted);
    }
    
    return 0;
}

在所有上述类型中,我可以简单地调用对象并提取看起来像调用默认 get() 方法的数据。有没有办法让 CInstance 类的对象在单独使用时触发方法。

示例: 我可以做类似的事情

CInstance obj;
std::cout << obj;

这将调用CInstance 中的默认方法。

【问题讨论】:

  • 不,你不能在 C++ 中做到这一点。您可以重载/专门化流的运算符
  • 您是否认为std::cout &lt;&lt; obj;obj 被“单独使用”的一个例子?它不是被使用作为&lt;&lt; 运算符的右手操作数吗?
  • 不确定我是否理解正确。您想在std::cout 中使用obj 的可能性吗?流,以便显示其内容?或者您想添加一种可能性,例如自动转换为std::string?
  • 顺便说一句,std::merge 可以完成您在Merge 中尝试做的所有工作。另外,如果你想要一个用现代 C++ 编写的模板化合并排序程序,see this link
  • 我刚刚意识到它所需要的只是operator&lt;&lt; over loading。就像@t.niese 回答的那样,除了operator&lt;&lt; 之外,我正在寻找更多类型的operator const char *() const

标签: c++ templates generics


【解决方案1】:

正如另一个答案中已经提到的,您可以创建自己的 operator&lt;&lt; 函数:

std::ostream & operator<<(std::ostream &stream, const CInstance &obj) {
    
    // stream <<  whatever you want to output

    return stream;
}

您还可以定义一个转换运算符。但是在使用它们之前,您应该三思而后行。它们可能导致不容易调试的问题,尤其是在省略explicit 时。您通常不应将它们用于日志记录/调试目的。如果您的类型表示一个字符串,并且您使用它可以轻松转换为 std::string,那么它可能没问题。

#include <iostream>
#include <string>

class CInstance {
    std::string str_ = "test";
public:
    explicit operator const std::string () const { return str_; }
};

int main() {
    CInstance obj;

    std::cout << (std::string)obj << std::endl;
    return 0;
}

如果您可以保证返回的const char * 的生命周期在调用后仍然有效,您还可以执行类似的操作(但我会避免该解决方案):

#include <iostream>
#include <string>

class CInstance {
    std::string str_ = "test";
public:
    operator const char *() const   { return str_.c_str(); }
};

int main() {
    CInstance t;

    std::cout << t << std::endl;
    return 0;
}

就个人而言,我会选择第一个解决方案。但这实际上取决于您是否真的有CInstance 的字符串表示形式,或者您是否想以不同的格式显示一些用于调试目的的内容。但是,我会避免使用 const char * 转换运算符的最后一个非显式版本。

【讨论】:

  • 很棒的技巧。我没有想过抛出重载operator&lt;&lt; 我问了这个问题,但是其中一些解决方案是在代码中实现的好东西。感谢分享。
  • @kishoredbn 您真的应该考虑是否要使用这些转换运算符。这些可能会导致难以调试代码问题,尤其是如果您省略了explicit。所以你真的应该考虑一下是否值得使用它们。
【解决方案2】:

在这种情况下,您可以像这样定义一个运算符

std::ostream & operator<<(std::ostream &stream, const CInstance &obj) {
    ... output obj however you want to the stream. For instance:
    stream << obj.getAge();
    return stream;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多