纯虚函数问题

问题描述 投票:0回答:2

我有一个基类,其中有一个纯虚函数,并且通过这个函数,我想在其他派生类中重写它(如果可能的话,在一些具有不同数量参数的派生类中)。

因此,在 MergeSort 子类中,我有 MSort 方法,该方法需要不同数量的参数,因为它是递归完成的。

因此,目前使用这些参数的功能我收到此错误 “MergeSort:”无法实例化抽象类。但是,如果我从基类重写 Sort 方法,效果很好,但我不需要一个参数。

我还尝试声明另一个具有不同数量参数的虚函数,并在 MergeSort 类中定义它,我得到了同样的结果。

我还想澄清一下,我有不同算法的其他子类(冒泡排序、插入排序等),这些子类的实现与 MergeSort (构造函数和排序函数)类似,但排序函数具有相同的参数数量(只是用于图形界面的)就像下面的基类一样。

那么是否可以有一个具有不同数量参数的重写方法?或者我上面所说的任何其他解决方案?

// BASE CLASS
// Forward declaration
class Interface;

/**
 * Base class from which the sorting algorithms classes will inherit (Polymorphic class) 
 * The base class will allow us to create a sequence with n elements    
 */
class SortingAlgorithms
{

protected:
    std::vector<sf::RectangleShape> sequence;       // vector which will contain a randomized sequence
    std::vector<sf::RectangleShape> sequenceCpy;    // a copy of sequence used for interaction features
    sf::RenderWindow& window;                       // initializes the window
    int minimum, maximum;                           // the range in which the elements will be randomized
    int elements;                                   // the number of elements which will be initialized

public:
    SortingAlgorithms();

    /** SortingAlgorithms() - class constructor which initializes the sequence
     *  @param min - the minimum value for randomizing
     *  @param max - the maximum value for randomizing
     *  @param els - the number of elements to generate
     *  @param win - since the window will be initialized only once (singleton pattern); 
     *               it will be needed to pass on this object to almost every function that has 
                     graphics features
     */
     SortingAlgorithms(int min, int max, int els, sf::RenderWindow& win);


     // A pure virtual function for overriding and param init which is what I described about win param from SortingAlgorithms constructor 
     virtual void Sort(std::unique_ptr<Interface>& init) = 0;
};



class MergeSort : public SortingAlgorithms
{
public:
    MergeSort(int min, int max, int els, sf::RenderWindow& win);
    
    void Merge(std::unique_ptr<Interface>& init, int first, int mid, int last);
    void MSort(std::unique_ptr<Interface>& init, int first, int last);
};
c++ oop polymorphism c++14 virtual-functions
2个回答
5
投票

如评论中所述,您必须对所有覆盖使用相同的签名。为此,您可以使用以下方法: 使用重写函数作为一种入口点,在其中调用执行排序的真实函数(可能是私有函数)。举例说明该方法:

class SortingAlgo
{
public:
    virtual void sort(int arr[], int n) = 0;
};

class BubbleSort: public SortingAlgo
{
public:
    void sort(int arr[], int n){
        this->bubble_sort(arr, n);
    }
private:
    void bubble_sort(int arr[], int n){
        //implemetation
    }
};

class MergeSort: public SortingAlgo
{
public:
    void sort(int arr[], int n){
        this->mergeSort(arr, 0, n - 1);
    }
private:
    void mergeSort(int arr[], int l, int r){
        //recursive implemetation
    }
    void merge(int arr[], int l, int m, int r){
        //implemenation
    }
};

-1
投票

这是解决重载具有不同数量参数的虚拟方法问题的另一种方法。如果

parameter-types
属于同一类型,则此操作有效。如果类型不同,那么您可能必须应用
templates
并使用
template-type deduction
或使用
variadic function templates
...

这里是示例代码和使用

GCC 10.2
编译生成的程序集,可以在 Compiler Explorer 上看到。

CPP

class Base {
public:
    virtual void foo(int a, int b, int c, int d) = 0;
};

class Bar : public Base {
public:
    // Requires All 4 Argumements - Don't Deafult any Parameter
    virtual void foo(int a, int b, int c, int d) override {
        // Use every parameter for this version of the function
    }
};

class Baz : public Base {
public:
    // Requires 3 Arguments - Default the Last Parameter
    virtual void foo(int a, int b, int c, int d = 0) override {
        // Use the first three parameters within this version of the function. 
    }
};

class Fiz : public Base {
public:
    // Requires 2 Arguments - Default the Last 2 Parameters
    virtual void foo(int a, int b = 0, int c = 0, int d = 0) override {
        // Use the first two parameters within this version of the function.   
    }
};

class Buz : public Base {
public:
    // Requires Only 1 Agument - Default All but the 1st Parameter
    virtual void foo(int a, int b = 0, int c = 0, int d = 0) override {
        // Use only the first parameter within this version of the function.
    }
};


int main() {
    Bar bar;
    bar.foo(1,2,3,4);
    Baz baz;
    baz.foo(5,6,7);
    Fiz fiz;
    fiz.foo(8,9);
    Buz buz;
    buz.foo(10);

    return 0;
} 

ASM

Bar::foo(int, int, int, int):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        mov     DWORD PTR [rbp-16], edx
        mov     DWORD PTR [rbp-20], ecx
        mov     DWORD PTR [rbp-24], r8d
        nop
        pop     rbp
        ret
Baz::foo(int, int, int, int):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        mov     DWORD PTR [rbp-16], edx
        mov     DWORD PTR [rbp-20], ecx
        mov     DWORD PTR [rbp-24], r8d
        nop
        pop     rbp
        ret
Fiz::foo(int, int, int, int):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        mov     DWORD PTR [rbp-16], edx
        mov     DWORD PTR [rbp-20], ecx
        mov     DWORD PTR [rbp-24], r8d
        nop
        pop     rbp
        ret
Buz::foo(int, int, int, int):
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        mov     DWORD PTR [rbp-16], edx
        mov     DWORD PTR [rbp-20], ecx
        mov     DWORD PTR [rbp-24], r8d
        nop
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 32
        mov     eax, OFFSET FLAT:vtable for Bar+16
        mov     QWORD PTR [rbp-8], rax
        lea     rax, [rbp-8]
        mov     r8d, 4
        mov     ecx, 3
        mov     edx, 2
        mov     esi, 1
        mov     rdi, rax
        call    Bar::foo(int, int, int, int)
        mov     eax, OFFSET FLAT:vtable for Baz+16
        mov     QWORD PTR [rbp-16], rax
        lea     rax, [rbp-16]
        mov     r8d, 0
        mov     ecx, 7
        mov     edx, 6
        mov     esi, 5
        mov     rdi, rax
        call    Baz::foo(int, int, int, int)
        mov     eax, OFFSET FLAT:vtable for Fiz+16
        mov     QWORD PTR [rbp-24], rax
        lea     rax, [rbp-24]
        mov     r8d, 0
        mov     ecx, 0
        mov     edx, 9
        mov     esi, 8
        mov     rdi, rax
        call    Fiz::foo(int, int, int, int)
        mov     eax, OFFSET FLAT:vtable for Buz+16
        mov     QWORD PTR [rbp-32], rax
        lea     rax, [rbp-32]
        mov     r8d, 0
        mov     ecx, 0
        mov     edx, 0
        mov     esi, 10
        mov     rdi, rax
        call    Buz::foo(int, int, int, int)
        mov     eax, 0
        leave
        ret
vtable for Buz:
        .quad   0
        .quad   typeinfo for Buz
        .quad   Buz::foo(int, int, int, int)
vtable for Fiz:
        .quad   0
        .quad   typeinfo for Fiz
        .quad   Fiz::foo(int, int, int, int)
vtable for Baz:
        .quad   0
        .quad   typeinfo for Baz
        .quad   Baz::foo(int, int, int, int)
vtable for Bar:
        .quad   0
        .quad   typeinfo for Bar
        .quad   Bar::foo(int, int, int, int)
typeinfo for Buz:
        .quad   vtable for __cxxabiv1::__si_class_type_info+16
        .quad   typeinfo name for Buz
        .quad   typeinfo for Base
typeinfo name for Buz:
        .string "3Buz"
typeinfo for Fiz:
        .quad   vtable for __cxxabiv1::__si_class_type_info+16
        .quad   typeinfo name for Fiz
        .quad   typeinfo for Base
typeinfo name for Fiz:
        .string "3Fiz"
typeinfo for Baz:
        .quad   vtable for __cxxabiv1::__si_class_type_info+16
        .quad   typeinfo name for Baz
        .quad   typeinfo for Base
typeinfo name for Baz:
        .string "3Baz"
typeinfo for Bar:
        .quad   vtable for __cxxabiv1::__si_class_type_info+16
        .quad   typeinfo name for Bar
        .quad   typeinfo for Base
typeinfo name for Bar:
        .string "3Bar"
typeinfo for Base:
        .quad   vtable for __cxxabiv1::__class_type_info+16
        .quad   typeinfo name for Base
typeinfo name for Base:
        .string "4Base"

正如我已经说过的,这将在简单的情况下起作用,即函数声明定义中每个自变量-参数放置的类型都是相同的类型。这里的技巧是采用参数数量最多的函数版本,并在抽象基类中的纯虚函数的声明中使用它。

现在,如果类型不同,您仍然可以执行此操作,但它们的位置必须匹配,例如:

class Base {
public:
    virtual void foo(int a, double b, char c) = 0;
};

class Bar : public Base {
public:
    virtual void foo(int a, double b, char c) override { } // uses all three
};

class Baz : public Base {
public:
    virtual void foo(int a, double b, char c = '') override {} // uses only the int and double
};

class Biz : public Base {
public:
    virtual void foo(int a, double = 0.0, char c = '') override{} // uses only the int
};

这应该也有效,但我还没有测试过。

© www.soinside.com 2019 - 2024. All rights reserved.