在声明之后使用方法扩展类功能

时间:2014-06-08 12:15:44

标签: c++ function class c++11 methods

我经常遇到我想要实现数据结构的问题,并希望允许用户使用功能扩展它;这是向数据结构添加功能但不添加字节。一个例子可以是使用sum方法扩展std :: vector:

#include <iostream>

#include <vector>

// for the header file
template<>
int std::vector<int>::sum();

//for the object file
template<>
int std::vector<int>::sum() {
    int s=0;
    for(auto v = this->begin(); v!=this->end(); ++v) s+=*v;
    return s;
}


int main() {
    std::vector<int> numbers;
    numbers.push_back(5);
    numbers.push_back(2);
    numbers.push_back(6);
    numbers.push_back(9);

    std::cout << numbers.sum() << std::endl;

    return 0;
}

请参阅:http://ideone.com/YyWs5r

所以这是非法的,因为有人可能不会向这样的类添加函数。显然这是c ++(11)的一些设计决定。它可以通过两种方式规避,即定义

int sum(std::vector<int> &v) { ... }

这就是std :: sort的工作原理,所以我猜这是c ++(11)的用途。我认为这是我所知道的最好的c ++方法。但是,它不允许我访问std :: vector的私有属性。也许我是邪恶的假设访问(排序)方法中的私有属性是公平的。但是,我经常希望我的类的用户不能访问某些东西,但是我希望允许我的扩展程序访问它们。例如,我可以想象std :: sort可以优化w.r.t.具体的容器实施知识和访问。

另一种方法是继承std :: vector,但由于以下原因,我觉得这是不可接受的:

  • 如果两方已经使用方法扩展了类,那么人们需要将一个子类转换为另一个子类。这是荒谬的,因为在没有实际更改字节的情况下将数据转换为数据,因为两个子类(可以)具有完全相同的内存实现和分段。还请注意,数据转换通常是样板代码,样板代码应该被认为是邪恶的。
  • 一个是不必要地将功能与数据结构混合在一起,例如,类名sum_vector或mean_vector完全是。

作为一个简短的提醒,我不是在寻找像“你不能用c ++这样做”的答案,我已经知道了(Add a method to existing C++ class in other file)。 但是,我想知道是否有一种很好的方法来执行功能类扩展。我该如何管理访问私有字段?什么原因导致我想要私人现场访问是不合理的;为什么我不能区分扩展程序用户访问权限?

注意:可以说扩展器需要受保护的访问权限而用户需要公共访问权限,但是,就像我说的那样,这将是继承的扩展方式,并且由于上述原因我强烈反对。

2 个答案:

答案 0 :(得分:2)

您永远不应该访问标准容器的私有成员,因为它们不是其接口的一部分

但是,您已经可以扩展标准容器的功能,如std::vector:即通过明智地使用迭代器和标准算法。

E.g。 sum功能由使用begin()的{​​{1}}和end()功能的非成员函数提供

std::vector

答案 1 :(得分:0)

考虑这样的事情:

#include <iostream>

class Foo{
    int a;
public:
    Foo(int a){this->a = a;}
    int getA(){return this->a;}
    void * extendedMethod(void *(*func)(int, char **, Foo*), int argc, char **argv){
        return func(argc, argv, this);
    }

};

void * extendFooWith(int argc, char **argv, Foo* self){
    /* You can call methods on self... but still no access to private fields */
    std::cout << self->getA();
    return self;
}

int main(int argc, char const *argv[])
{
    Foo foo(5);
    foo.extendedMethod(extendFooWith, 0 /*argc*/, NULL /*argv*/);
    return 0;
}

这是我想用方法扩展类的最好方法。访问私有字段的唯一方法是从extendedMethod()内部开始,即这样的事情是可能的:return func(this->a, argv, this);但是它不再是那种通用的。改进它的一种方法是检查内部extendedMethod()传递了什么类型的指针,并根据它访问您感兴趣的私有字段并将其传递给func(),但这需要添加代码{ {1}}对于所有其他方法,您将使用。

扩展您的课程