具有静态(内联)方法的从未实例化类的基类

Posted

技术标签:

【中文标题】具有静态(内联)方法的从未实例化类的基类【英文标题】:Base class for never instantiated classes having a static (inlined) method 【发布时间】:2014-01-28 10:07:10 【问题描述】:

我有一堆类(我从不实例化)以不同的方式实现相同的静态内联方法。我试图了解这些班级是否可以有一个共同的父母。 目的不是进行虚拟调用,而只是为想要以不同方式再次编写实现该方法的新类的任何人强制一个结构。我可以这样做吗?我开始认为这不是 C++ 提供的一种功能。

class XXX 
public:
    ///Should force any derived class to implement
    ///bool compute(const unsigned char i1, const unsigned char i2);
;

class GreaterThan : public XXX 
public:
    static inline bool compute(const unsigned char i1, const unsigned char i2) 
        return i1 > i2;
    
;

class NotGreaterThan : public XXX 
public:
    static inline bool compute(const unsigned char i1, const unsigned char i2) 
        return i1 <= i2;
    
;

class NotLessThan : public XXX  ///This should not compile
public:
    static inline bool compute2(const unsigned char i1, const unsigned char i2) 
        return i1 >= i2;
    
;

[...]

在基类中定义纯虚方法compute 不允许我在派生类中定义静态方法。当我将它用作仿函数时,让方法不是静态的会迫使我实例化该类,并且基本上会阻止内联。

注意:here 提出了类似的问题。

编辑:可能,这也不应该编译:

class LessThan : public XXX  ///Also this should not compile
public:
    static inline bool compute(const float i1, const float i2) 
        return i1 < i2;
    
;

【问题讨论】:

【参考方案1】:

你想要的叫做静态多态。

您根本不需要继承。在您的示例中,这应该强制 XXX 的用户将 bool compute(const unsigned char i1, const unsigned char i2); 实现为静态方法:

template< typename C >
class XXX 
public:
    static void CallCompute(const unsigned char i1, const unsigned char i2)
    
        const bool result = C::compute( i1, i2 );
        // use result somehow
    
;

顺便注意一下,他们可能将compute() 实现为bool compute(const T1 i1, const T2 i2);,其中T1 和T2 可以是任何整数或浮点类型。

【讨论】:

您有一个非常有趣的观点:用法将定义必须如何实现类。但正如您所指出的,这只提供了有限的控制,此外它似乎对“开发人员”不友好:):我们没有提供关于如何实现比较类的明确信息。 @Antonio 好吧,他们应该阅读有关如何使用您的课程的文档。除此之外,如果缺少compute() 方法,编译器会抛出错误,这对开发人员非常友好。 当然,这不会导致任何编译时错误,除非您实际执行某些操作来触发 CallCompute 的实例化(比如调用它)。 根据讨论,我对问题进行了(显式:))编辑,以便我们可以更准确地确定可以做什么和不可以做什么。 @Antonio 编辑:class LessThan : public XXX 不会编译,如果 XXX 是模板类。【参考方案2】:

这应该几乎可以满足您的需求:

#include <iostream>

template <typename Algorithm>
class UnsignedCharFunction 
    public:
    typedef Algorithm algorithm_type;
    static bool compute(const unsigned char i1, const unsigned char i2) 
        return call(algorithm_type::do_compute, i1, i2);
    

    private:
    static bool call(
        bool (*f)(const unsigned char, const unsigned char),
        const unsigned char i1, const unsigned char i2) 
        return f(i1, i2);
    
;

class GreaterThan : public UnsignedCharFunction<GreaterThan> 
    friend class UnsignedCharFunction<GreaterThan>;

    private:
    static bool do_compute(const unsigned char i1, const unsigned char i2) 
        return i1 > i2;
    
;


class Invalid : public UnsignedCharFunction<Invalid> 
    friend class UnsignedCharFunction<Invalid>;

    private:
    #define N 2
    #if N == 1
    // Fails
    static bool no_do_compute(const unsigned char i1, const unsigned char i2) 
        return i1 >= i2;
    
    #elif N == 2
    // Fails
    static bool do_compute(char i1, char i2) 
        return i1 >= i2;
    
    #endif
;


int main() 
    std::cout << "A > B:" << GreaterThan::compute('A', 'B') << '\n'
              << "B > A:" << GreaterThan::compute('B', 'A') << '\n';
    // If you comment next line, there will be no error.
    Invalid::compute('A', 'B');

这几乎是模板的适当实例化 - 只有在使用该函数时才会出现编译器错误。

关于内联:

volatile bool value; 
int main() 
    value = GreaterThan::compute('A', 'B');


00000000004005a0 <main>:
  4005a0: movb   $0x0,0x200aa5(%rip)        # 60104c <value>
  4005a7: xor    %eax,%eax
  4005a9: retq   
  4005aa: nopw   0x0(%rax,%rax,1)

代码将在这个简单的小程序中完全省略。

另一个内联:

volatile bool value;
volatile unsigned char a;
volatile unsigned char b;
int main() 
    value = GreaterThan::compute(a, b);


00000000004005a0 <main>:
  4005a0: movzbl 0x200aa5(%rip),%edx        # 60104c <b>
  4005a7: movzbl 0x200a9f(%rip),%eax        # 60104d <a>
  4005ae: cmp    %al,%dl
  4005b0: setb   %al
  4005b3: mov    %al,0x200a95(%rip)        # 60104e <value>
  4005b9: xor    %eax,%eax
  4005bb: retq   
  4005bc: nopl   0x0(%rax)

均使用“g++ -std=c++11 -O3 -g”编译

【讨论】:

好东西!但我想知道这是否有机会被内联......我会说不会...... 为了测试内联,我认为输入值(在这种情况下为“A”和“B”)在编译时不应该知道。 @Antonio 它是内联的!【参考方案3】:

基类对它的派生类一无所知,所以 没有真正的方法可以断言任何事情。在很多情况下, 您可以通过使基类成为模板来解决此问题 它将派生类作为参数。那行不通 然而,在这里,因为你想要一个静态检查导致 派生时立即出现编译时错误,并且在那 那个时候,派生类不是一个完整的类型,你不能 使用其中的任何功能(即使在sizeof 表达)。

【讨论】:

以上是关于具有静态(内联)方法的从未实例化类的基类的主要内容,如果未能解决你的问题,请参考以下文章

Typescript - 从基类中的静态方法实例化子类,使用 args 并引用其他静态方法

确定子类是不是具有在 Python 中实现的基类方法

如图java代码里面,不需要用new关键字实例化类就可以直接使用类里面的对象吗?

实例化类的时候代码运行顺序

杂谈 论实例化类的第六种方式

这是一种在 javascript 中实例化类的方法吗? [复制]