在构造函数 c++ 中指向不同 class 的指针初始化
Pointer initialization to different class in constructor c++
我在 BirdHouse 的构造函数初始化列表中初始化指向 Bird 的指针时遇到问题。好像没有指向我要指向的对象
这是鸟 class:
class Bird
{
std::string name;
static int objectCount;
public:
Bird () : name("Bird #" + std::to_string(objectCount))
{
++objectCount;
}
Bird (const Bird& bb) : name(bb.name + " copy")
{
}
friend class BirdHouse;
};
这里是 BirdHouse class:
class BirdHouse
{
Bird b;
Bird * bp;
Bird & br;
public:
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
void print() const
{
std::cout << "Bird b = " << b.name << std::endl;
std::cout << "Bird * bp = " << bp->name << std::endl;
std::cout << "Bird & br = " << br.name << std::endl;
}
};
当我想在 main() 中调用 BirdHouse::print() 时,程序崩溃了:
int main()
{
Bird b1;
Bird b2;
Bird b3 = b2;
BirdHouse bh1(b1,b2,b3);
// bh1.print(); // I can't call it because b2 points to weird stuff
return 0;
}
我应该如何初始化 BirdHouse 对象以使其指向适当的 Bird 对象?
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
aa
、bb
和 cc
是按值传递的参数,这些参数对于您的构造函数而言是本地的。但是,您存储了一个指向 bb
的指针和一个对 cc
的引用,它们在构造函数结束时都变为悬空状态。
当您尝试访问 print()
中的一个悬挂成员时,您会触发未定义的行为,在您的情况下会发生崩溃。不要那样做。
打开你的编译器警告可能会通知你这个问题。
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
这里你按值获取参数,从而创建一个副本。然后您继续存储一个指针并引用这些副本,这些副本将在构造函数结束时被破坏。现在,无论何时您尝试访问这些,都会调用未定义的行为。
要解决此问题,您可以改为引用您的论点:
BirdHouse(Bird& aa, Bird& bb, Bird& cc) : b(aa), bp(&bb), br(cc) {}
崩溃是因为未定义的行为,因为你保存了一个指向按值传递的参数的指针,一旦函数returns.
据我所知,有两种可能的解决方案:要么将变量作为指针传递,要么通过引用传递。但是,请注意,如果 BirdHouse
对象的生命周期长于您传入的对象(作为指针或引用)的生命周期,您将再次出现未定义的行为。
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
// ^^^^^^^, this is a temporary object (i.e., it won't exist
// after the constructor completes
上面你取了一个临时参数的地址。如果您尝试在构造函数的主体中使用 bp
。但是,一旦构造函数完成,临时对象就消失了,但 bp
仍然指向该内存地址。最后,一旦执行 print
函数,它就会取消引用一个不再指向有效对象且行为未定义的指针。
根据您的用例,您可以将构造函数更改为:
A)
BirdHouse(Bird aa, Bird& bb, Bird& cc) : b(aa), bp(&bb), br(cc) {}
B)
BirdHouse(Bird aa, Bird* bb, Bird& cc) : b(aa), bp(bb), br(cc) {}
注意:调用者需要明确的是,bb
和br
的生命周期至少需要和生命周期一样长BirdHouse
个实例。
我在 BirdHouse 的构造函数初始化列表中初始化指向 Bird 的指针时遇到问题。好像没有指向我要指向的对象
这是鸟 class:
class Bird
{
std::string name;
static int objectCount;
public:
Bird () : name("Bird #" + std::to_string(objectCount))
{
++objectCount;
}
Bird (const Bird& bb) : name(bb.name + " copy")
{
}
friend class BirdHouse;
};
这里是 BirdHouse class:
class BirdHouse
{
Bird b;
Bird * bp;
Bird & br;
public:
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
void print() const
{
std::cout << "Bird b = " << b.name << std::endl;
std::cout << "Bird * bp = " << bp->name << std::endl;
std::cout << "Bird & br = " << br.name << std::endl;
}
};
当我想在 main() 中调用 BirdHouse::print() 时,程序崩溃了:
int main()
{
Bird b1;
Bird b2;
Bird b3 = b2;
BirdHouse bh1(b1,b2,b3);
// bh1.print(); // I can't call it because b2 points to weird stuff
return 0;
}
我应该如何初始化 BirdHouse 对象以使其指向适当的 Bird 对象?
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
aa
、bb
和 cc
是按值传递的参数,这些参数对于您的构造函数而言是本地的。但是,您存储了一个指向 bb
的指针和一个对 cc
的引用,它们在构造函数结束时都变为悬空状态。
当您尝试访问 print()
中的一个悬挂成员时,您会触发未定义的行为,在您的情况下会发生崩溃。不要那样做。
打开你的编译器警告可能会通知你这个问题。
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
这里你按值获取参数,从而创建一个副本。然后您继续存储一个指针并引用这些副本,这些副本将在构造函数结束时被破坏。现在,无论何时您尝试访问这些,都会调用未定义的行为。
要解决此问题,您可以改为引用您的论点:
BirdHouse(Bird& aa, Bird& bb, Bird& cc) : b(aa), bp(&bb), br(cc) {}
崩溃是因为未定义的行为,因为你保存了一个指向按值传递的参数的指针,一旦函数returns.
据我所知,有两种可能的解决方案:要么将变量作为指针传递,要么通过引用传递。但是,请注意,如果 BirdHouse
对象的生命周期长于您传入的对象(作为指针或引用)的生命周期,您将再次出现未定义的行为。
BirdHouse(Bird aa, Bird bb, Bird cc) : b(aa), bp(&bb), br(cc) {}
// ^^^^^^^, this is a temporary object (i.e., it won't exist
// after the constructor completes
上面你取了一个临时参数的地址。如果您尝试在构造函数的主体中使用 bp
。但是,一旦构造函数完成,临时对象就消失了,但 bp
仍然指向该内存地址。最后,一旦执行 print
函数,它就会取消引用一个不再指向有效对象且行为未定义的指针。
根据您的用例,您可以将构造函数更改为:
A)
BirdHouse(Bird aa, Bird& bb, Bird& cc) : b(aa), bp(&bb), br(cc) {}
B)
BirdHouse(Bird aa, Bird* bb, Bird& cc) : b(aa), bp(bb), br(cc) {}
注意:调用者需要明确的是,bb
和br
的生命周期至少需要和生命周期一样长BirdHouse
个实例。