use*_*630 -3 c++ header getter-setter
C++ 类是否有可能像我们在 Java 中一样包含自己类型的实例?例如,这样的事情:
public class A {
private A a1;
private A a2;
A getA1(){
return a1;
}
A getA2(){
return a2;
}
void setA1(A a1){
this.a1 = a1;
}
void setA2(A a2){
this.a2 = a2;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我想在 C++ 中做同样的事情或解决方法。
是的,它在 C++ 中是可行的。但是语法会有点不同:
this-> 代替 this.
private:/public:而不是private/public每个成员
记得;在课程结束时
A*作为成员(或std::uniqe_ptr<A>或std::shared_ptr<A>或std::weak_ptr<A>)。
第 1-3 项仅仅是语法。第 4 项是 Java 和 C++ 之间的本质区别:
在 Java 中,对象变量是对对象的引用,而在 C++ 中,对象变量是一个值。这就是为什么你不能在 C++ 中保持你自己的直接成员,因为对象的大小将是无限的 (A 持有 A 的实际值,持有 A 的实际值,......递归)。
在 Java 中,当 A 持有 A 时,它只持有对另一个 A的引用(是的,您仍然可以递归访问引用的 A,但它不是您大小的一部分,您只是持有对它的引用,它存储在其他地方在内存中。增加的大小只是参考的大小)。
您可以在 C++ 中使用引用变量或指针实现类似的语义,通过添加&引用或*指针:
A& a2 = a1; // a2 is a reference to A, assigned with a reference to a1
// note that a1 above is assumed to be also of type A&
A* a2 = a1; // a2 is a pointer to A, assigned with the address stored in a1
// note that a1 above is assumed to be also of type A*
Run Code Online (Sandbox Code Playgroud)
Java 垃圾收集器回收未使用的内存,而在 C++ 中,程序员需要处理它,可能使用 C++ 工具,例如智能指针。
Java Garbage Collector 通过Trace by Reachability回收未使用的内存,C++ 智能指针基于作用域生存期。此外,C++shared_ptr基于引用计数,这有其优点,但受引用周期的影响,可能会发生内存泄漏,应通过正确设计代码来避免这种情况。
C++ 版本的“保持自己”可能看起来像下面的任何一个(或它们的变体),具体取决于确切的需要:
class A {
A* a1 = nullptr;
A* a2 = nullptr;
public:
A* getA1(){
return a1;
}
A* getA2(){
return a2;
}
void setA1(A* a1){
this->a1 = a1;
}
void setA2(A* a2){
this->a2 = a2;
}
};
Run Code Online (Sandbox Code Playgroud)
class A {
std::unique_ptr<A> a1 = nullptr;
std::unique_ptr<A> a2 = nullptr;
public:
A* getA1(){
return a1.get();
}
A* getA2(){
return a2.get();
}
void setA1(std::unique_ptr<A> a1){
this->a1 = std::move(a1);
}
void setA2(std::unique_ptr<A> a2){
this->a2 = std::move(a2);
}
};
Run Code Online (Sandbox Code Playgroud)
*需要确保避免循环所有权泄漏。
class A {
std::shared_ptr<A> a1 = nullptr;
std::shared_ptr<A> a2 = nullptr;
public:
auto getA1(){
return a1;
}
auto getA2(){
return a2;
}
void setA1(std::shared_ptr<A> a1){
this->a1 = a1;
}
void setA2(std::shared_ptr<A> a2){
this->a2 = a2;
}
};
Run Code Online (Sandbox Code Playgroud)
*的选项std::weak_ptr在可能的循环依赖的情况下是相关的,a1 和 a2 在其他地方拥有并且可能不存在。
class A {
std::weak_ptr<A> a1 = nullptr;
std::weak_ptr<A> a2 = nullptr;
public:
std::shared_ptr<A> getA1(){
return a1.lock();
}
std::shared_ptr<A> getA2(){
return a2.lock();
}
void setA1(std::shared_ptr<A> a1){
this->a1 = a1;
}
void setA2(std::shared_ptr<A> a2){
this->a2 = a2;
}
};
Run Code Online (Sandbox Code Playgroud)
选项 4 代码示例:http : //coliru.stacked-crooked.com/a/92d6004280fdc147
请注意,使用A&(对 A 的引用)作为成员不是一种选择,因为在 C++ 中引用变量比天主教婚礼强,它们在变量的生命周期内无法重新分配给另一个引用。并且它们必须在出生时分配给有效的参考。
但是,如果a1和a2是在对象出生时已知的,在对象的生命周期内永远不会改变并保持活动状态,那么以下选项也是可能的:
*此选项主要是为了表明可以保存引用,但在大多数情况下,指针选项(如选项 1)或 const 指针成员会更合适。
class A {
A& a1;
A& a2;
public:
A(A& a1, A& a2): a1(a1), a2(a2) {}
// using ref to self as a placeholder
// to allow the creation of "the first A"
A(): a1(*this), a2(*this) {}
A& getA1(){
return a1;
}
A& getA2(){
return a2;
}
};
int main() {
A a1;
A a2(a1, a1);
}
Run Code Online (Sandbox Code Playgroud)
下面的最后一个也是最后一个选项主要是提出继续执行选项 5 并允许更改 A 持有的参考的可能性。
从 C++20 开始,此选项是可能的。但是,需要注意的是,为此目的使用指针很可能是更好的选择。
*从 C++20 开始,注意这个选项主要是为了展示可能性,指针在这里可能是更好的选择。
class A {
// all same as in option 5
public:
void set(A& a1, A& a2){
A other(a1, a2);
// placement new that changes internal ref
// is valid since C++20
new (this) A(other);
}
};
Run Code Online (Sandbox Code Playgroud)
选项 5b 的代码:http : //coliru.stacked-crooked.com/a/43adef3bff619e99
另请参阅:为什么我可以为引用分配新值,以及如何使引用引用其他内容?