【问题标题】:How to determine which derived class is being pointed to when using an array of pointers使用指针数组时如何确定指向哪个派生类
【发布时间】:2010-07-23 19:15:35
【问题描述】:

我正在编写一个可以掷骰子和掷硬币的 C++ 程序。我需要使用继承和多态。我的虚拟功能设置正确。在我的基类(aRandomNumberGenerator)中,我有一个虚函数生成。在 main() 中,我需要一个包含 2 个基类指针的数组,这些指针指向我的派生类(aDie 和 aCoin)。调用 generate() 函数时,如何知道数组中指向的是哪个派生类??

代码:

int main()
{
    int n;
    int frequency1 = 0; // count of 1s rolled
    int frequency2 = 0; // count of 2s rolled
    int frequency3 = 0; // count of 3s rolled
    int frequency4 = 0; // count of 4s rolled
    int frequency5 = 0; // count of 5s rolled
    int frequency6 = 0; // count of 6s rolled
    int face; // stores most recently rolled value
    int numHeads = 0; // count of heads
    int numTails = 0; // count of tails
    int side; // stores most recently flipped value

    cout << "Enter a seed number: "; // promp for user to enter a seed number
    cin >> n;
    cout << endl;
    cout << endl;

    aRandomNumberGenerator number(n);
    aDie die(n, n);
    aCoin coin(n, n);

    aRandomNumberGenerator *games[2]; // array of 2 base class pointers

    for(int i=0; i <= 2; i++)  
      games[i]->generate();  


    // output the seed number entered by the user
    cout << "the seed entered is: " << die.inputSeed(n) << endl;
    cout << endl;
    cout << endl;

    // summarize results for 600 flips of a coin
    for(int counter2 = 0; counter2 < 600; counter2++)
    {
        side = generate();

        // determine flip value 0/1 and increment appropriate counter
        switch ( side )
        {
        case 0:
            ++numHeads;
            break;
        case 1:
            ++numTails;
            break;
        default:
            cout << "can only be heads or tails";
        }
    }

    // summarize results for 600 rolls of a die
    for(int counter1 = 0; counter1 < 600; counter1++)
    {
        face = generate();

        // determine roll value 1-6 and increment appropriate counter
        switch ( face )
        {
        case 1:
            ++frequency1;
            break;
        case 2:
            ++frequency2;
            break;
        case 3:
            ++frequency3;
            break;
        case 4:
            ++frequency4;
            break;
        case 5:
            ++frequency5;
            break;
        case 6:
            ++frequency6;
            break;
        default:
            cout << "7 doen't exist on a die!";
        }
    }

    // output results
    cout << "Heads: " << numHeads << endl;
    cout << "Tails: " << numTails << endl;
    cout << "1: " << frequency1 << endl;
    cout << "2: " << frequency2 << endl;
    cout << "3: " << frequency3 << endl;
    cout << "4: " << frequency4 << endl;
    cout << "5: " << frequency5 << endl;
    cout << "6: " << frequency6 << endl;

    cout << endl;
    cout << endl;
    system ("pause");
    return 0;

【问题讨论】:

  • 使用多态性的全部意义在于你不必担心类型。

标签: c++ polymorphism


【解决方案1】:

使用 dynamic_cast。

if (Derived1* ptr = dynamic_cast<Derived1*>(basepointer)) {
    // Do something with ptr
}

但是,对于常规方法调用,您不需要确定它。只需调用基类上的方法,它就会被分派到正确的派生类——这就是继承的用途。

编辑:对于常规的 virtual 方法,您可以只在基指针上调用它,而无需知道或关心 Derived 是什么,您将获得正确的函数调用。

【讨论】:

    【解决方案2】:
    aRandomNumberGenerator *games[2]; // array of 2 base class pointers 
    
    for(int i=0; i <= 2; i++)   
      games[i]->generate(); 
    

    首先,让我们在处理其他事情之前让它工作。

    您正在创建一个数组,该数组将保存指向两个 aRandomNumberGenerator 对象的指针,但您从未创建 aRandomNumberGenerator 对象本身。 games[0]games[1] 持有无意义的值。此外,在循环中,您还可以访问不存在的games[2]

    更新: 出于某种原因,另一个回答者决定使用我讨厌的奇怪的速记版本的代码,并且可能会混淆任何没有经验的 C++ 代码(OP 显然是),所以让我们自己做吧:

    Derived1* ptr = dynamic_cast<Derived1*>(basepointer)
    if (ptr != null) 
    { 
        // Do something with ptr 
    } 
    

    【讨论】:

    • 我修复了我的 for 循环,我需要像普通对象一样创建每个对象吗?还有什么是dynamic_cast代码?前任。 aRandomNumberGenerator games[0] = &aCoin aRandomNumberGenerator games[1] = &aDie
    • 我使用了缩短的版本,因为它确保 ptr 如果不是 Derived1 就不会被滥用。如果 OP 不是经验丰富的 C++ 编码人员,这是额外的保护级别。
    【解决方案3】:

    您可以使用 RTTI(typeid 和 dynamic_cast),或者添加一个在实现中标识类的虚函数(滚动您自己的 RTTI)。

    一般来说,如果可以避免,添加依赖于实现的代码(关心确切类型的代码)被认为是不好的做法,但在实现本身中除外。 “实现”不仅仅指特定的派生类,还指特定于该实现的配对/相关类。

    尝试通过多态性将特定于您的具体实现的 switch/else-if 语句滚动到实现本身。

    http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.6

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-14
      • 2012-07-05
      • 2016-02-19
      • 1970-01-01
      • 2020-04-07
      • 2011-11-04
      • 2021-08-17
      相关资源
      最近更新 更多