必须使用指向抽象类的指针会导致困难

发布于 2024-12-11 04:09:37 字数 1088 浏览 0 评论 0原文

我的第一个问题...

我想使用一个抽象类 A 从中派生出一个类 B (以及类 B2>B3,...)。我明白,为了统一处理它们,我必须使用指向基类的指针,所以这里的变量是A*类型。

在下面的例子中,我想在函数f中填充aa,其类型为vector。由于我只能使用引用,并且变量在 f 末尾失去作用域,因此我无法访问 mainaa 条目的成员> 不再了。

什么可以解决这个问题?

#include <vector>
#include <iostream>


class A {
    public:
        virtual int getVar(int, int) = 0;
};

class B : public A {
    public:
        B(std::vector<std::vector<int> > var) : var_(var) {};
        int getVar(int i, int j) { return var_[i][j]; }
    private:
        std::vector<std::vector<int> > var_;
};

void f(std::vector<A*>& aa) {
    std::vector<std::vector<int> > var(1, std::vector<int>(1));
    var[0][0] = 42;

    B b(var);

    aa.push_back(&b);
}

int main() {
    std::vector<A*> aa;

    f(aa);

    std::cout << aa[0]->getVar(0, 0) << std::endl;

    return 0;
}

My first question here...

I want to use an abstract class A from which i derive a class B (and classes B2, B3, ...). I understood that in order to handle them uniformly, I have to use pointers to the base class, so here variables of type A*.

In the example below, I want to fill aa which is of type vector<A*> in function f. Since I can only use references and the variables lose their scope at the end of f, I cannot access the members of the entries of aa in main anymore.

What could be a solution to this problem?

#include <vector>
#include <iostream>


class A {
    public:
        virtual int getVar(int, int) = 0;
};

class B : public A {
    public:
        B(std::vector<std::vector<int> > var) : var_(var) {};
        int getVar(int i, int j) { return var_[i][j]; }
    private:
        std::vector<std::vector<int> > var_;
};

void f(std::vector<A*>& aa) {
    std::vector<std::vector<int> > var(1, std::vector<int>(1));
    var[0][0] = 42;

    B b(var);

    aa.push_back(&b);
}

int main() {
    std::vector<A*> aa;

    f(aa);

    std::cout << aa[0]->getVar(0, 0) << std::endl;

    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

朮生 2024-12-18 04:09:37
B b(var);
aa.push_back(&b);

它正在推送本地变量的地址。这就是问题的原因,因为局部变量在从函数返回时被销毁,但 aa 仍然包含指向不存在对象的指针。这样的指针称为悬空指针,使用它调用未定义的行为 - 这是 C++ 中最危险、最令人恼火的方面之一。

使用new

aa.push_back(new B(var));

现在它应该可以工作了。

重要:不要忘记将~A()设为虚拟:

class A {
    public:
        virtual ~A() {} //MUST DO IT
        virtual int getVar(int, int) = 0;
};

这是必要的,否则您将无法删除派生类型的对象(在明确定义的类型中)方式),使用基本类型的指针

B b(var);
aa.push_back(&b);

It is pushing the address of the local variable. That is the cause of the problem, because the local variable gets destroyed on returning from the functon, but aa still contains the pointer to the non-existing object. Such a pointer is called dangling pointer using which invokes undefined behavior - which is one of the most dangerous and irritating aspect of C++.

Use new:

aa.push_back(new B(var));

Now it should work.

Important : Don't forget to make ~A() virtual:

class A {
    public:
        virtual ~A() {} //MUST DO IT
        virtual int getVar(int, int) = 0;
};

It is necessary otherwise you wouldn't be able to delete objects of derived type (in a well-defined way), using the pointers of base type.

下雨或天晴 2024-12-18 04:09:37

您观察到的问题是范围问题。

C++ 中有两种不同的分配策略:

  • 自动存储:在块 ({ }) 内声明的对象,其生命周期以块结束
  • 动态存储:使用 new 分配的对象> (或者new[],如果它是一个数组)

如果你想创建一个变量并在它自己的作用域之外访问它,那么你需要依赖动态存储。然而,它不是免费的,因为这样你就会面临生命周期管理问题,因为它现在是手动的。

因此,建议使用 RAII 习惯用法,将动态分配对象的生命周期与自动分配对象的生命周期联系起来。在您的情况下,使用智能指针(或容器)。

使用 C++11:

int main() {
  std::vector< std::unique_ptr<A> > aa;
  foo(aa);

  std::cout << aa.front()->getVar(0,0) << "\n";
}

并相应地更新 foo

void foo(std::vector< std::unique_ptr<A> >& aa) {
  std::vector<std::vector<int> > var(1, std::vector<int>(1));
  var[0][0] = 42;

  aa.push_back(new B(var));
}

The problem you observe is a matter of scope.

There are two different allocation strategies in C++:

  • automatic storage: an object declared within a block ({ }), its lifetime ends with the block
  • dynamic storage: an object allocated with new (or new[] if it's an array)

If you want to create a variable and access it outside of its own scope, then you need to rely on dynamic storage. However, it's not free, because then you expose yourself to lifetime management issues, since it's now manual.

The recommendation is therefore to use the RAII idiom, to tie the lifetime of a dynamically allocated object to that of an automatically allocated one. In your case, using smart pointers (or containers).

Using C++11:

int main() {
  std::vector< std::unique_ptr<A> > aa;
  foo(aa);

  std::cout << aa.front()->getVar(0,0) << "\n";
}

And updating foo accordingly:

void foo(std::vector< std::unique_ptr<A> >& aa) {
  std::vector<std::vector<int> > var(1, std::vector<int>(1));
  var[0][0] = 42;

  aa.push_back(new B(var));
}
把人绕傻吧 2024-12-18 04:09:37

问题出在您的 f() 函数内。您正在创建一个自动分配的对象,一旦退出该函数,该对象就不再存在。您必须使用new 在堆上分配它。

B* b = new B(var);
aa.push_back(b);

当然,当你不再使用它时,你必须自己释放它。

int main() {
    ...


    for (std::vector<A*>::iterator it = aa.begin(); it != aa.end(); ++it)
    {
        delete *it;
    }
    return 0;
}

The problem is within your f() function. You are creating a automatically allocated object, that ceases to exist, once you exit the function. You have to allocat it on the heap, using new.

B* b = new B(var);
aa.push_back(b);

Of course you have to free it on your own when you do not use it any more.

int main() {
    ...


    for (std::vector<A*>::iterator it = aa.begin(); it != aa.end(); ++it)
    {
        delete *it;
    }
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文