C++ 必须使用指向抽象类的指针会带来困难

C++ 必须使用指向抽象类的指针会带来困难,c++,pointers,abstract-class,C++,Pointers,Abstract Class,我的第一个问题是 我想使用一个抽象类A,从中派生一个类B(和类B2,B3,…)。我知道为了统一处理它们,我必须使用指向基类的指针,所以这里是A*类型的变量 在下面的示例中,我想在函数f中填充aa类型的vector。由于我只能使用引用,并且变量在f末尾失去作用域,因此我无法再访问main中aa项的成员 这个问题的解决方案是什么 #include <vector> #include <iostream> class A { public: virt

我的第一个问题是

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

在下面的示例中,我想在函数
f
中填充
aa
类型的
vector
。由于我只能使用引用,并且变量在
f
末尾失去作用域,因此我无法再访问
main
aa
项的成员

这个问题的解决方案是什么

#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;
}
#包括
#包括
甲级{
公众:
虚拟int getVar(int,int)=0;
};
B类:公共A{
公众:
B(std::vectorvar):var_(var){};
intgetvar(inti,intj){returnvar_ui][j];}
私人:
std::向量变量;
};
空f(标准::向量和aa){
std::vector var(1,std::vector(1));
var[0][0]=42;
B(var);
aa.推回(&b);
}
int main(){
std::载体aa;
f(aa);
std::coutgetvar(0,0)
它正在推送局部变量的地址。这是问题的原因,因为从函数返回时局部变量会被破坏,但
aa
仍然包含指向不存在对象的指针。这种指针被称为using,它调用未定义的行为,这是最危险的行为之一C++的刺激性方面。

使用
新建

aa.push_back(new B(var));
现在应该可以了

重要提示:别忘了将
~A()
虚拟化:

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

这是必需的,否则您将无法使用基类型的指针(以定义良好的方式)删除派生类型的对象。

问题出在您的
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;
}
intmain(){
...
for(std::vector::iterator it=aa.begin();it!=aa.end();++it)
{
删除*它;
}
返回0;
}

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

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";
}

非常感谢您快速详细的回答!
int main() {
  std::vector< std::unique_ptr<A> > aa;
  foo(aa);

  std::cout << aa.front()->getVar(0,0) << "\n";
}
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));
}