سؤال

I have an abstract class implemented by several concrete classes with different memory footprint, in order to use polymorphism.

#include <iostream>
using namespace std;

class abstractFoo {
public:
    virtual void method() = 0;
};

First concrete class:

class concreteFoo1 : public abstractFoo {
private:
    int member1;
public:
    concreteFoo1() {
        cout << "Constructing Foo1" << endl;
        member1 = 1;
    }
    virtual void method() {
        cout << "Foo1 member: " << member1 << endl;
    }
};

Another concrete class:

class concreteFoo2 : public abstractFoo {
private:
    int member1;
    int member2;
public:
    concreteFoo2() {
        cout << "Constructing Foo2" << endl;
        member1 = 2;
        member2 = 3;
    }
    void method() {
        cout << "Foo2 members: " << member1 << ", " << member2 << endl;
    }
};

What I want to do is to declare an object of abstract type abstractFoo and passing it as a parameters in a function which will create it as an object of either concrete type concreteFoo1 or concreteFoo2. I first use the usual way, with a pointer passed in parameter:

enum typeFoo {FOO1, FOO2};

void createFoo(typeFoo type, abstractFoo *foo) {
    switch (type) {
    case FOO1:
        foo = &concreteFoo1();
        break;
    case FOO2:
        foo = &concreteFoo2();
        break;
    }
}

int main() {
    abstractFoo *foo = new concreteFoo1();
    createFoo(FOO2, foo);
    foo->method();        //Not expected result!
    return 0;
}

Output is:

Constructing Foo1
Constructing Foo2
Foo1 member: 1

The problem is I can't initialize foo as an object of abstract type, and if I initialize as concreteFoo1, as I did in this example, the foo pointer will still point to it, even after calling createFoo method.

In order to make it works, I was told to pass a pointer to a pointer in parameter:

enum typeFoo {FOO1, FOO2};

void createFoo(typeFoo type, abstractFoo **foo) {
    switch (type) {
    case FOO1:
        *foo = new concreteFoo1();
        break;
    case FOO2:
        *foo = new concreteFoo2();
        break;
    }
}
int main() {
    abstractFoo *foo = new concreteFoo1();
    createFoo(FOO2, & foo);
    foo->method();        //Expected result
    return 0;
}

Output:

Constructing Foo1
Constructing Foo2
Foo2 members: 2, 3

Well, this solution work, but I am not very pleased by it: I still can't create a pointer to an abstract type, so I have to construct an object I will not use in astractFoo* foo = new concreteFoo1(), and the memory allocated to it is never freed, so I think I will end with a memory leak.

Is there a way to create AbstractFoo** , a pointer to a pointer to an abstract type, without constructing an object?

So, can you confirm that a double pointer is the rigth solution to my problem, and if so, can you answer my two problems? If not, how should I do?

هل كانت مفيدة؟

المحلول 2

Well, I just found that you can create pointer with operator new, so I answer my own question:

enum typeFoo {FOO1, FOO2};
void createFoo(typeFoo type, abstractFoo **foo) {
    switch (type) {
    case FOO1:
        *foo = new concreteFoo1();
        break;
    case FOO2:
        *foo = new concreteFoo2();
        break;
    }
}
int main() {
    abstractFoo **foo = new abstractFoo*;
    createFoo(FOO2, foo);
    abstractFoo *foo2Ptr = *foo;
    foo2Ptr->method();        //Expected result
    delete foo2Ptr;
    createFoo(FOO1, foo);
    abstractFoo *foo1Ptr = *foo;
    foo1Ptr->method();        //Expected result
    delete foo1Ptr;

    return 0;
}

Output:

Constructing Foo2
Foo2 members: 2, 3
Constructing Foo1
Foo1 member: 1

Any comment, especially if I should use reference or smart pointers?

نصائح أخرى

If you use a std::unique_ptr<abstractFoo>, as a return type and combine it with the factory pattern, you solve both the memory allocation issues and the creation issue.

Note that you'll need a virtual destructor in abstractFoo.

A double pointer is not the C++ thing to do. It's a remainder from C. Passing a pointer by reference would be more C++-ish. Not using pointers, but smart pointers instead if even more C++-ish.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top