在C/C++中是否可能模仿Go的接口?

huangapple go评论82阅读模式
英文:

Is it possible to mimic Go interface in C/C++?

问题

在Go语言中,如果类型拥有接口定义的所有方法,那么它可以被赋值给该接口变量,而无需显式地继承它。

在C/C++中是否可能模拟这个特性?

英文:

In Go, if the type has all the methods that the interface defined then it can be assigned to that interface variable without explicitly inheriting from it.

Is it possible to mimic this feature in C/C++?

答案1

得分: 8

是的。您可以使用纯抽象类,并使用模板类来包装实现抽象类的类型,以便它们扩展抽象类。这是一个简单的示例:

#include <iostream>

// 在函数签名中使用的接口类型
class Iface {
public:
        virtual int method() const = 0;
};
 
// 用于实现 Iface 的类型的模板包装器
template <typename T>
class IfaceT: public Iface {
public:
        explicit IfaceT(T const t):_t(t) {}
        virtual int method() const { return _t.method(); }
 
private:
        T const _t;
};

// 实现 Iface 的类型
class Impl {
public:
        Impl(int x): _x(x) {}
        int method() const { return _x; }
 
private:
        int _x;
};
 

// 接受 Iface 参数的方法
void printIface(Iface const &i) {
        std::cout << i.method() << std::endl;
}
 
int main() {
        printIface(IfaceT<Impl>(5));
}
英文:

Yes. You can use a pure abstract class, and use a template class to wrap types "implementing" the abstract class so that they extend the abstract class. Here's a barebones example:

#include &lt;iostream&gt;

// Interface type used in function signatures.
class Iface {
public:
        virtual int method() const = 0;
};
 
// Template wrapper for types implementing Iface
template &lt;typename T&gt;
class IfaceT: public Iface {
public:
        explicit IfaceT(T const t):_t(t) {}
        virtual int method() const { return _t.method(); }
 
private:
        T const _t;
};

// Type implementing Iface
class Impl {
public:
        Impl(int x): _x(x) {}
        int method() const { return _x; }
 
private:
        int _x;
};
 

// Method accepting Iface parameter
void printIface(Iface const &amp;i) {
        std::cout &lt;&lt; i.method() &lt;&lt; std::endl;
}
 
int main() {
        printIface(IfaceT&lt;Impl&gt;(5));
}

答案2

得分: 3

是的,当然。

实际上,处理运行时接口的代码是用C语言编写的。
http://code.google.com/p/go/source/browse/src/pkg/runtime/iface.c

英文:

Yes, of course.

In fact the code that handles interfaces in the runtime is written in C.
http://code.google.com/p/go/source/browse/src/pkg/runtime/iface.c

答案3

得分: 2

在C++20中有***概念***,它们看起来有点像Go语言的接口

https://en.cppreference.com/w/cpp/language/constraints

// 给定以下数据类型
struct Type1 {
    bool m(int i) {
        return i > 0;
    }
};

struct Type2 {
    bool m(int i, int defaultArg = 0) {
        return (i % 2) == defaultArg;
    }
};

#include <iostream>
#include <string>


// 我声明了这个概念
template<typename T>
concept HasUsefulMethod = requires(T a, int b) {
    { a.m(b) } -> std::same_as<bool>;
};


// 所以我可以声明以下函数,它可以接受
// 所有实现了m(int) -> bool的类
std::string calculateResult(HasUsefulMethod auto x, int i = 0){
    return std::string {
        x.m(i) ? "yes" : "no"
    } + "!";
}



int main()
{
    std::cout << "calculate result for struct Type1: " << calculateResult(Type1{}, -1)  << std::endl;
    std::cout << "calculate result for struct Type2: " << calculateResult(Type2{})  << std::endl;
}

我在这篇帖子中回复是因为我认为C++的概念是一个非常有用的功能

编辑

它似乎甚至可以与默认参数一起工作,参见Type2::m

https://wandbox.org/permlink/gvlr0nFi56El8vcu

英文:

In C++20 there are conceps, they seems quite bit like go interfaces

https://en.cppreference.com/w/cpp/language/constraints

// Given the following data types
struct Type1 {
    bool m(int i) {
        return i &gt; 0;
    }
};

struct Type2 {
    bool m(int i, int defaultArg = 0) {
        return (i % 2) == defaultArg;
    }
};

#include &lt;iostream&gt;
#include &lt;string&gt;


// I declare this concept
template&lt;typename T&gt;
concept HasUsefulMethod = requires(T a, int b) {
    { a.m(b) } -&gt; std::same_as&lt;bool&gt;;
};


// So I can declare the following function that can take
// all classes that implement an m(int) -&gt; bool
std::string calculateResult(HasUsefulMethod auto x, int i = 0){
    return std::string {
        x.m(i) ? &quot;yes&quot; : &quot;no&quot;
    } + &quot;!&quot;;
}



int main()
{
    std::cout &lt;&lt; &quot;calculate result for struct Type1: &quot; &lt;&lt; calculateResult(Type1{}, -1)  &lt;&lt; std::endl;
    std::cout &lt;&lt; &quot;calculate result for struct Type2: &quot; &lt;&lt; calculateResult(Type2{})  &lt;&lt; std::endl;
}

I'm necromancing this post because I think that C++'s concepts are a very useful functionality

Edit

it seems to work even with default parameters, see Type2::m

https://wandbox.org/permlink/gvlr0nFi56El8vcu

答案4

得分: 0

我猜使用GObject可能会有一些粗略的等价物。

英文:

I guess some rough equivalence might be feasible with GObject.

答案5

得分: 0

我为C++尝试了一下。最终得到了一个能够工作的东西,但是它是一个宏马戏团:https://github.com/wkaras/c-plus-plus-misc/tree/master/IFACE。一个接口是两个指针,一个指向对象数据成员,另一个指向类似于虚表的东西(一个指向调用成员函数的thunk函数的指针结构)。这些表(不幸地)在运行时生成。从接口转换为子接口需要进行unordered_map查找,所以平均时间复杂度为O(1)。与将派生类指针/引用转换为基类指针/引用相比,后者的最坏情况时间复杂度为O(1)。

它并不是很实用,但它确实表明接口可以(干净地)通过相对较少的努力添加到C++中。在某些情况下,接口比基于继承的面向对象更好,而且试图保持C++的精简已经不太可能了。

英文:

I took a stab at it for C++. I ended up with something that works, but is a macro circus: https://github.com/wkaras/c-plus-plus-misc/tree/master/IFACE . An interface is two pointers, one to object data members, and another to the equivalent of a virtual table (a structure of pointers to thunk functions that call member functions). These tables are (unfortunately) generated at run-time. Conversion from an interface to a sub-interface requires an unordered_map look up, so it's O(1) time complexity on average. As compared with converting a derived class pointer/reference to one to a base class, which is O(1) worst-case.

It's not very usable, but it does show that interfaces could be (cleanly) added to C++ with relatively little effort. There are cases where interfaces are better than inheritance-based OO, and the cow is well out of the barn as far as trying to keep C++ small.

huangapple
  • 本文由 发表于 2012年1月23日 18:24:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/8970157.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定