Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding custom methods to std::vector or typdef

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");
like image 898
toxicate20 Avatar asked May 29 '13 11:05

toxicate20


2 Answers

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++.

like image 60
Zdeslav Vojkovic Avatar answered Oct 23 '22 23:10

Zdeslav Vojkovic


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.
like image 4
Arne Mertz Avatar answered Oct 24 '22 01:10

Arne Mertz