Adding custom methods to std::vector or typdef

2019-06-22 08:44发布

问题:

So I have the following code that makes it possible to "search" for a string of an object in a vector.

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <string>

struct migObj
{
    migObj(const std::string& a_name, const std::string& a_location) : name(a_name),             location(a_location) {}
    std::string name;
    std::string location;
};

int main()
{
    typedef std::vector<migObj> migVec;
    migVec v;
    v.push_back(migObj("fred", "belfast"));
    v.push_back(migObj("ivor", "london"));

    // Search by name.
    const std::string name_to_find = "ivor";
    auto i = std::find_if(v.begin(), v.end(), [&](const migObj& obj) { return name_to_find == obj.name;});
    if (i != v.end())
    {
        std::cout << i->name << ", " << i->location << "\n";
    }

    return 0;
}

The code below the commecnt "search by name" is responsible for this result. What I want to do is make a method that is either added to the std::vector or to the typedef migVec, so I can call

v.myNewSearchFunction("ivor");

回答1:

You can't do that: C++ doesn't have extension methods similar to what you have in C#.

You could derive your class from vector, but then you have to change all the client code. Besides, as Roddy points out, std::vector doesn't have a virtual destructor, so deriving from it is a bad idea in general.

IMO, writing a simple function would be much better choice. Additional benefit is that it would also work for most other containers (e.g. std::list) and be more compatible with most of algorithms in STL which are also typically free functions.

So you would have this instead:

myNewSearchFunction(v, "ivor"); // instead of v.myNewSearchFunction("ivor");

Internally, this function does std::find_if(v.begin(), v.end(), ....

BTW, please note that it would be better to use std::begin(v), std::end(v) than v.begin(), v.end(). This lets you run the same code on e.g. arrays.

Putting things into classes isn't always the best choice in C++.



回答2:

That's not possible. At least not in any way that is recommendable.

To elaborate a bit: You cannot "extend" C++ classes to have more methods than in their primary definition. In other words, you cannot redefine the class or "reopen" its definition to add more features.

What you should do: Write a free function, taking the vector as first parameter. That is as good as writing a method, has no caveats. The generated assembler would likely be identical to a new method:

migVec::const_iterator findByName(migvec const& mv, std::string const& name) {
  return std::find_if(std::cbegin(mv), std::cend(mv), [&](const migObj& obj) { 
    return name == obj.name;
  });
}

//...
auto pos = findByName(v, "ivor");

What you could theoretically do but shouldn't:

  • Derive from std::vector. Don't do this. It's not designed to be derived from, and you could run into tons of trouble.
  • Specialize std::vector<migObj>. It is allowed to provide full specializations of standard library templates. However, you'd have to provide the complete definition of the specialized vector, meaning alls its standard methods and the new method you want it to have. To achieve this, you'd either have to practically copy std::vector's defintion from your library header (wich is not portable) or roll your own definition, wich is tedious work. Just don't go there.