Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 封装:公共成员与公共方法_C++_C++14_Encapsulation - Fatal编程技术网

C++ 封装:公共成员与公共方法

C++ 封装:公共成员与公共方法,c++,c++14,encapsulation,C++,C++14,Encapsulation,假设我有一个名为PointerSet的类。它本质上是一个向量,通过使用std::lower_bound(但它的工作原理并不重要,因此我将不深入讨论) 模板 类指针集 { ... 公众: 无效插入(T&); 无效擦除(T&); 无效擦除(const std::vector&); }; 拥有“功能隧道”会影响性能吗?(我不知道这个技术术语,但在我的脑海中它就是我所说的。它是一个函数调用一个具有完全相同目的的函数。)请参见版本1 第1版:创建成员方法 ... template<typenam

假设我有一个名为
PointerSet
的类。它本质上是一个
向量
,通过使用
std::lower_bound
(但它的工作原理并不重要,因此我将不深入讨论)

模板
类指针集
{
...
公众:
无效插入(T&);
无效擦除(T&);
无效擦除(const std::vector&);
};
拥有“功能隧道”会影响性能吗?(我不知道这个技术术语,但在我的脑海中它就是我所说的。它是一个函数调用一个具有完全相同目的的函数。)请参见版本1

第1版:创建成员方法

...

template<typename T>
class Node
{
    PointerSet<T> Links;
public:
    void insertLink(T& p){ Links.insert(p); }
    void eraseLink(T& p){ Links.erase(p); }
    void eraseLink(const std::vector<T>& p){ Links.erase(p); }
};

class bar;
class foo : public Node<bar> { };    // now foo can insert links to bars.

...
。。。
模板
类节点
{
指针集链接;
公众:
void insertLink(T&p){Links.insert(p);}
无效擦除链接(T&p){Links.erase(p);}
void eraseLink(const std::vector&p){Links.erase(p);}
};
分类栏;
类foo:公共节点{};//现在,foo可以插入指向条的链接。
...
第2版:只需使用公共成员即可

...

class bar;
struct foo
{
    PointerSet<bar> Links;    // Use Links directly
};
。。。
分类栏;
结构foo
{
指针集链接;//直接使用链接
};

以下哪种方法是最好的?我考虑的是性能和调试的易用性。

除非您想限制可以在该数据成员上执行的操作,否则我建议使用public成员。如果您所做的只是用您自己的方法名包装这些方法,那么将它们放在那里是没有意义的。

除非您希望限制可以在该数据成员上执行的操作,否则我建议使用public成员。如果您所做的只是用自己的方法名包装这些方法,那么将它们放在那里是没有意义的。

  • 通常,如果IS-A关系不受尊重,您应该避免公共派生,因为它会导致该组合的耦合度更高
  • 您还应该避免使用公共成员,因为这会使应用程序在将来更难维护
  • 如果您可以在第二个示例中直接使用
    指针集
    ,那么在版本1中,您也可以直接从
    指针集
    派生。因此,这种比较是不公平的
在实践中,可接受的折衷在很大程度上取决于每个类的实际用途。如果额外的间接性不能带来任何好处(减少编译依赖性、访问/可见性控制、额外功能、代码重用机会……),则它们是无用的。

  • 通常,如果IS-A关系不受尊重,您应该避免公共派生,因为它会导致该组合的耦合度更高
  • 您还应该避免使用公共成员,因为这会使应用程序在将来更难维护
  • 如果您可以在第二个示例中直接使用
    指针集
    ,那么在版本1中,您也可以直接从
    指针集
    派生。因此,这种比较是不公平的
在实践中,可接受的折衷在很大程度上取决于每个类的实际用途。如果额外的间接性不能带来任何好处(减少编译依赖性、访问/可见性控制、额外功能、代码重用机会等),则它们是无用的

拥有“功能隧道”会影响性能吗

很可能不是。特别是因为您在这里处理的是模板,所以定义都是可见的,并且编译器很容易内联。请查看此链接:

我所做的是编译这两个代码片段。首先,从节点类调用函数

#include <vector>

// these functions are not defined, so that the compiler
// cannot inline them or optimize them out
void insert_impl(void const*);
void erase_impl(void const*);
void erase_impl_vec(void const*);

template<typename T>
class PointerSet
{
public:
    void insert(T& v) { insert_impl(&v); }
    void erase(T& v) { erase_impl(&v); }
    void erase(const std::vector<T>& v) {
        erase_impl_vec(&v);
    }
};

template<typename T>
class Node
{
    PointerSet<T> Links;
public:
    void insertLink(T& p){ Links.insert(p); }
    void eraseLink(T& p){ Links.erase(p); }
    void eraseLink(const std::vector<T>& p){ Links.erase(p); }
};

int main()
{
    Node<int> n;

    int x;
    n.insertLink(x);
    n.eraseLink(x);

    std::vector<int> v;
    n.eraseLink(v);
}
正如您在link()中所看到的,编译器为每个对象输出相同的程序集

main:                                   # @main
        push    rbx
        sub     rsp, 48
        lea     rbx, [rsp + 12]
        mov     rdi, rbx
        call    insert_impl(void const*)
        mov     rdi, rbx
        call    erase_impl(void const*)
        xorps   xmm0, xmm0
        movaps  xmmword ptr [rsp + 16], xmm0
        mov     qword ptr [rsp + 32], 0
        lea     rdi, [rsp + 16]
        call    erase_impl_vec(void const*)
        mov     rdi, qword ptr [rsp + 16]
        test    rdi, rdi
        je      .LBB0_3
        call    operator delete(void*)
.LBB0_3:
        xor     eax, eax
        add     rsp, 48
        pop     rbx
        ret
        mov     rbx, rax
        mov     rdi, qword ptr [rsp + 16]
        test    rdi, rdi
        je      .LBB0_6
        call    operator delete(void*)
.LBB0_6:
        mov     rdi, rbx
        call    _Unwind_Resume
GCC_except_table0:
        .byte   255                     # @LPStart Encoding = omit
        .byte   3                       # @TType Encoding = udata4
        .byte   41                      # @TType base offset
        .byte   3                       # Call site Encoding = udata4
        .byte   39                      # Call site table length
        .long   .Lfunc_begin0-.Lfunc_begin0 # >> Call Site 1 <<
        .long   .Ltmp0-.Lfunc_begin0    #   Call between .Lfunc_begin0 and .Ltmp0
        .long   0                       #     has no landing pad
        .byte   0                       #   On action: cleanup
        .long   .Ltmp0-.Lfunc_begin0    # >> Call Site 2 <<
        .long   .Ltmp1-.Ltmp0           #   Call between .Ltmp0 and .Ltmp1
        .long   .Ltmp2-.Lfunc_begin0    #     jumps to .Ltmp2
        .byte   0                       #   On action: cleanup
        .long   .Ltmp1-.Lfunc_begin0    # >> Call Site 3 <<
        .long   .Lfunc_end0-.Ltmp1      #   Call between .Ltmp1 and .Lfunc_end0
        .long   0                       #     has no landing pad
        .byte   0                       #   On action: cleanup
main:#@main
推送rbx
副区长,48
lea rbx,[rsp+12]
mov rdi,rbx
调用insert_impl(void const*)
mov rdi,rbx
调用擦除\u impl(无效常量*)
xorps xmm0,xmm0
movaps xmmword ptr[rsp+16],xmm0
mov qword ptr[rsp+32],0
李尔迪[rsp+16]
调用擦除执行向量(无效常量*)
mov rdi,qword ptr[rsp+16]
测试rdi,rdi
乙脑LBB0_3
呼叫操作员删除(无效*)
.LBB0_3:
异或eax,eax
加上rsp,48
流行音乐
ret
mov-rbx,rax
mov rdi,qword ptr[rsp+16]
测试rdi,rdi
乙脑LBB0_6
呼叫操作员删除(无效*)
.LBB0_6:
mov rdi,rbx
打电话(解除)(恢复)
GCC_除表0外:
.byte 255#@LPStart Encoding=省略
.byte 3#@t类型编码=udata4
.byte 41#@t类型基偏移量
.byte 3#调用站点编码=udata4
.字节39#调用站点表长度
.long.Lfunc_begin0-.Lfunc_begin0#>>呼叫站点1>呼叫站点2>呼叫站点3
拥有“功能隧道”会影响性能吗

很可能不是。特别是因为您在这里处理的是模板,所以定义都是可见的,并且编译器很容易内联。请查看此链接:

我所做的是编译这两个代码片段。首先,从节点类调用函数

#include <vector>

// these functions are not defined, so that the compiler
// cannot inline them or optimize them out
void insert_impl(void const*);
void erase_impl(void const*);
void erase_impl_vec(void const*);

template<typename T>
class PointerSet
{
public:
    void insert(T& v) { insert_impl(&v); }
    void erase(T& v) { erase_impl(&v); }
    void erase(const std::vector<T>& v) {
        erase_impl_vec(&v);
    }
};

template<typename T>
class Node
{
    PointerSet<T> Links;
public:
    void insertLink(T& p){ Links.insert(p); }
    void eraseLink(T& p){ Links.erase(p); }
    void eraseLink(const std::vector<T>& p){ Links.erase(p); }
};

int main()
{
    Node<int> n;

    int x;
    n.insertLink(x);
    n.eraseLink(x);

    std::vector<int> v;
    n.eraseLink(v);
}
正如您在link()中所看到的,编译器为每个对象输出相同的程序集

main:                                   # @main
        push    rbx
        sub     rsp, 48
        lea     rbx, [rsp + 12]
        mov     rdi, rbx
        call    insert_impl(void const*)
        mov     rdi, rbx
        call    erase_impl(void const*)
        xorps   xmm0, xmm0
        movaps  xmmword ptr [rsp + 16], xmm0
        mov     qword ptr [rsp + 32], 0
        lea     rdi, [rsp + 16]
        call    erase_impl_vec(void const*)
        mov     rdi, qword ptr [rsp + 16]
        test    rdi, rdi
        je      .LBB0_3
        call    operator delete(void*)
.LBB0_3:
        xor     eax, eax
        add     rsp, 48
        pop     rbx
        ret
        mov     rbx, rax
        mov     rdi, qword ptr [rsp + 16]
        test    rdi, rdi
        je      .LBB0_6
        call    operator delete(void*)
.LBB0_6:
        mov     rdi, rbx
        call    _Unwind_Resume
GCC_except_table0:
        .byte   255                     # @LPStart Encoding = omit
        .byte   3                       # @TType Encoding = udata4
        .byte   41                      # @TType base offset
        .byte   3                       # Call site Encoding = udata4
        .byte   39                      # Call site table length
        .long   .Lfunc_begin0-.Lfunc_begin0 # >> Call Site 1 <<
        .long   .Ltmp0-.Lfunc_begin0    #   Call between .Lfunc_begin0 and .Ltmp0
        .long   0                       #     has no landing pad
        .byte   0                       #   On action: cleanup
        .long   .Ltmp0-.Lfunc_begin0    # >> Call Site 2 <<
        .long   .Ltmp1-.Ltmp0           #   Call between .Ltmp0 and .Ltmp1
        .long   .Ltmp2-.Lfunc_begin0    #     jumps to .Ltmp2
        .byte   0                       #   On action: cleanup
        .long   .Ltmp1-.Lfunc_begin0    # >> Call Site 3 <<
        .long   .Lfunc_end0-.Ltmp1      #   Call between .Ltmp1 and .Lfunc_end0
        .long   0                       #     has no landing pad
        .byte   0                       #   On action: cleanup
main:#@main
推送rbx
副区长,48
lea rbx,[rsp+12]
mov rdi,rbx
调用insert_impl(void const*)
mov rdi,rbx
调用擦除\u impl(无效常量*)
xorps xmm0,xmm0
movaps xmmword ptr[rsp+16],xmm0
mov qword ptr[rsp+32],0
李尔迪[rsp+16]
调用擦除执行向量(无效常量*)
mov-rdi,qw