不能使外部类成为内部类内的成员对象

cannot make outer class as member object inside inner class

本文关键字:内部类 成员对象 外部 不能      更新时间:2023-10-16

我对以下代码有 3 个问题:

class cb
{
public:
int y_;
class iterator
{
public:     
//void func() { y_ = 5; }   // (1)      
private:
int x_;
//cb a;                    // (2)       
};  
void funcCB() { }
};
class Human
{
public: 
void func() const {
cb c;                        // (3)
c.funcCB();
}
//  (4)
};

1-为什么我不能像(1)那样在内部类内部使用外部类的成员变量y_

2-为什么我不能像in(2)那样从内部类的外部类创建对象,而只能创建指针和引用?

3-为什么如果我将(3)处的行移动到(4cb c;)处的行,则会出现编译错误?

  1. 您不能使用外部类字段,因为它不像您的类迭代器可以直接访问它。首先,您为什么要访问该字段?我会考虑先重新设计您的解决方案。但正如你所愿,这里是你可以做些什么来解决这个问题。您需要引用作为您的父对象的对象
class cb
{
public:
cb(): it(*this) {} // Passing the reference to ourself for iterator object init to have access in iterator class access to y_ field.
int y_;
class iterator
{
public:
iterator(cb& ob): a(ob) {}
void func() { a.y_ = 5; }         
private:
int x_;
cb& a;             // Reference to parent object             
};  
iterator it;  // Added because I don't see the point where you don't want to have that object in your cb class.
void funcCB() { }
};
  1. 我不确定你想在这里实现什么。它将抛出不完整的类型,因为您将想要创建 cb 对象,您将在其中创建迭代器对象,您将在其中创建 cb 对象,您将在其中再次创建迭代器,以便获得无限递归(如果我理解正确的话)。当您将迭代器指向具体对象时,它将停止循环。

  2. 您应该将类 cb funcCB 更改为void funcCB() const {},因为否则在类 Human 中可以理解,在 func() 中,这是 const 函数,您想
  3. 调用 funcCB(),它不会修改来自 Human 类的对象 c,并且限定符之间存在差异,因为在这种情况下您没有const 函数。您还可以在 Human类中删除 func 的 const 限定符,这也将起作用。当您不更改限定符时,这里会发生错误,因为当您有 const 函数在其中创建一些对象以进一步使用时,以及当您将对象作为类字段并且您调用无法更改 Human 类和 CB 类的状态的函数时,情况会有所不同funcCB 没有等效的 const 函数。

为什么我不能像 (1) 那样在内部类内部使用外部类的成员变量y_?

因为y_是类cb的非静态数据成员,这意味着我们必须在特定cb对象上访问它。但问题来了。赋值语句y_ = 5;等效于:

vvvv--------------->this points to an object of type iterator and not cb
this->y_ = 5;

在上面显示的等效语句中,this指针指向类型为iterator的当前实例,而不是cb。但是由于要访问y_我们必须使用cb类型对象,因此我们得到了提到的错误。

基本上y_应该在类型为cb的对象上访问。例如,您可以func具有类型为cb&的参数,然后访问y_如下所示:

class cb
{
public:
int y_;
class iterator
{
public:  
//------------vvv------------------->pass object of type cb by reference 
void func(cb& it) { it.y_ = 5; }   // (1) OK NOW
//----------------------^^---------->access member y_ on object it
private:
int x_;

};  
void funcCB() { }
};

为什么我不能像 in(2) 一样从内部类的外部类创建对象,但我只能创建指针和引用?

因为在#2点,类cb不完整,因此在第#2点我们无法创建类型为cb的非静态数据成员。这可以从完整的类型文档中看出,其中指出:

以下任何上下文都需要类型T才能完成:

  • 声明类型T的非静态类数据成员;

这意味着在第#2点,我们不能为类型cb的非静态数据成员提供声明,但我们仍然可以为cb&cb*类型的非静态数据成员提供声明,因为我们可以有一个指针或对不完整类型的引用,如cb.


为什么如果我在 (3)cb c处移动行; 在 (4) 处移动行我得到编译错误?

如果将第#3行 (cb c;) 移动到第#4行,则不会收到任何编译时错误。演示

class Human
{
public: 
void func() const {
//cb c;                        // (3)
//c.funcCB();
}
cb c;     // (4)  perfectly fine 
};

如果我不太明白这一点,请原谅我 - 我的C++有点生锈。

关于问题(1)——你试过"这个"关键词吗?

例如:

void func() { this->y_ = 5; } 

这是一个与您的示例几乎相同的示例:

C++中的"this"指针

对于问题 2,您要求递归包含对象。这就像在说,什么是洋葱?这是一个含有洋葱的果皮。嗯,里面的洋葱也是一个皮,里面有一个洋葱,然后是一个皮,然后是一个洋葱,等等。如果没有一些停止机制(洋葱可能是一个核心,它不包含任何东西),洋葱对象的第一个实例化将无限循环,直到所有内存都用完。

作为参考,内存只能在需要时检索,而不是之前检索。

对于问题3,我懒惰地说,他们只是规则。

更新:我现在不在工作,所以我有更多的时间做更多的研究。正如我所说,我的C++有点生锈。

本质上,对于问题 1,您尝试做的是从类"迭代器"访问类"cb"的成员。我的研究表明,仅仅因为"迭代器"是"cb"的一个子类,它就没有任何特殊的访问权限。因此,您不能从"迭代器"访问"cb::y_",也不能使用"this->y_"。类内的方法(函数)可以直接访问"y_"。子类不能。

请注意以下成功编译

class cb {
public:
int y_;
class iterator {
public:     
void func() { 
cb *z = new cb();
z->y_ = 5;
}   // (1)      
private:
int x_;
cb *a;                    // (2)       
};  
void funcCB() { }
};
class Human
{
public: 
void func() const {
cb c;                        // (3)
c.funcCB();
}
//  (4)
cb *z;
};

这可能不是你想要完成的,但我希望你想做的事情不能按照你想要的方式完成。最好的办法是将"迭代器"实现为与"cb"不同的自己的类,并使其成为"cb"的"友元"类。或者也许更好,更简单,只需在类中包含一组迭代器方法。这些方法将具有对所有类属性的完全访问权限。

另请注意指针对"cb"的引用。它不会编译为子类中的直接对象实例化。再次,洋葱问题。

附带说明一下,请记住C++不是帕斯卡。它不是Java。它可以做子类,但正如你所看到的,它不能很好地做它们,或者至少,它不像其他语言那样做它们。您最好创建与其他类完全不同的每个类,而不是正常的继承。这有点非正式的"C++之道"。