如何从已在其中创建的不同类对象中访问类对象的成员函数?
Posted
技术标签:
【中文标题】如何从已在其中创建的不同类对象中访问类对象的成员函数?【英文标题】:How do you access member functions of a class object from within a different class object that has been created in it? 【发布时间】:2021-12-15 12:23:54 【问题描述】:class Class1 //Would be object mClass1
public:
void Function1()
a++;
private:
int a = 0;
Class2 mClass2;
(此处在空白处编辑以澄清 Class2 不是在 Class1 之后定义的;它们在单独的文件中。)
class Class2 //Would be object mClass2
public:
Function2()
Function1(); // Would be from mClass1
所以 Class1 创建了 Class2 对象的实例,而 Class2 对象有一个成员函数,该成员函数想要访问“父”对象的成员函数,而不使用继承。
我不知道我具体需要搜索什么来了解这一点。它是否与取消引用 new
指针有关?构造函数类型/初始化?它有术语吗? “嵌套类”会调出定义在另一个类中的类,而这不是。
【问题讨论】:
【参考方案1】:没有继承就无法获得“父类”。因此,您应该只将函数作为参数传递,如果您多次使用它,可能在类 2 的构造函数中。例如:https://www.cprogramming.com/tutorial/function-pointers.html
【讨论】:
【参考方案2】:你不能这样做。在定义Class1
时,Class2
尚不可知,因此不可能创建Class1::mClass2
数据成员。但是这个问题可以通过在Class1
之前定义Class2
来解决,并且在类之外并且只在Class1
之后实现Class2::Function2()
。
至于在Function2()
内部调用Function1()
,Class2
需要知道调用Function1()
的对象。您可以使用在构造函数中初始化的引用成员:
// Forward-declaration of Class1 so that Class2 will be able to define
// references or pointers to Class1.
class Class1;
class Class2
public:
// Constructor that requires a reference to our parent object.
explicit Class2(Class1& parent)
: parent_(parent)
// Just declare the function. We need to implement it later, outside
// this class definition because Class1 is not fully known yet and as
// a result we can't have calls to Function1() because the compiler
// doesn't know that function yet.
void Function2();
private:
// This is just a reference, so it works even if Class1 is not fully
// known yet.
Class1& parent_;
;
class Class1
public:
void Function1() /* ... */
private:
int a = 0;
Class2 mClass2*this; // Pass ourself as the parent object.
;
// Class1 is fully known now, so we can do calls to Function1().
inline void Class2::Function2()
parent_.Function1();
这会起作用,但它有一个重要的含义:它禁用了Class2
的赋值运算符。在这种情况下,这可能是您想要的,因为 Class2
的两个副本可能不应该具有相同的 Class1
父对象。
但是,我不明白您为什么需要这样做。它无缘无故地使事情复杂化。为什么不简单地传递Function2()
应该用作函数参数的Class1
对象呢?所以:
class Class1;
class Class2
public:
void Function2(Class1& c1_obj);
;
class Class1
public:
void Function1() /* ... */
private:
int a = 0;
Class2 mClass2;
;
inline void Class2::Function2(Class1& c1_obj)
c1_obj.Function1();
所以每当Class1
需要调用Class2::Function2()
时,只需将*this
传递给它。它更简单,并且没有持有指向另一个对象的引用或指针的缺点。
【讨论】:
我得到 "unknown override specifier" @Class2 mClass2*this;
,之后还有八个相关错误。也许是因为我不使用内联。有必要吗?
@Wicky 工作正常:godbolt.org/z/qMeWenjz9 是的,inline
对于在头文件中但在类之外实现的函数是必需的。 (除了函数模板,不需要inline
。)如果你在.cpp
文件中实现函数,那么inline
就不需要了。【参考方案3】:
使用规范类 - 无法做到这一点,因为 Class2
在 Class1
中是不完整的,并且如果您在 Class1
内声明 Class2
(作为嵌套类),它将无法访问 @ 987654326@,因为Class1
不完整!
看起来像一个无法解决的悖论?它在 OOP 领域是无法解决的,但可以像 Nikos 所展示的那样躲避。但是在某些情况下,未定义类型的问题可以在 C++ 或类似的面向概念的语言中通过使用 CRTP - Curiously recurring template 来解决。
在您的用例中是否可能以及它的复杂程度取决于您追求的目的。这是一个自相矛盾的 CRTP 行为示例 - 基类的成员能够调用派生类的成员:
#include <iostream>
template < class T>
class Base
public:
template <class U>
struct Accessor : public U
static void evoke_foo( T& obj)
return (obj.*(static_cast< void(T::*)() >(&Accessor::foo))) ();
;
void evoke( )
Accessor<T>::evoke_foo( *static_cast<T*>(this) );
;
class Derived : public Base<Derived>
protected:
void foo() std::cout << "Foo is called" << std::endl;
;
int main()
Derived a;
a.evoke(); // evoke belongs to base.
现在,如果我们想在这里自动确定foo()
的返回类型,这将成为一段极其复杂的代码。在evoke
方法的标准同名实现中解决了一些类似的问题。
【讨论】:
“没办法,因为Class2在Class1中是不完整的” 其实很简单。只需在Class1
之前定义Class2
:-P(请参阅我的答案。)
@Nikos 那么它将无法访问Class1
OP 显示的方式。声明的预声明和分离定义在某些情况下有效(这是常见的方法),但在某些情况下这是不可能的。引用方法通常包含在 CRTP 中(标准组件通过 reference_wrapper 和 trait 类做到这一点)
好吧,通常你总是将声明和定义分开。您在.h
文件中声明您的类,并在.cpp
文件中定义“重”函数,在.h
文件的最底部将“较轻”函数定义为inline
。一段时间以来,这一直是 C++ 中最常用的方法。大多数人不想在类 API 中乱扔函数定义。
@NicosC 是的,对于大多数编译器中替代方案开发不完善的部分,尽管这对于标准组件及其仅标头性质来说是个问题。只有 C++20 通过引入模块解决了它(并增加了新问题)。并且不清楚 OP 的想法。在您的版本中 Class2 和 Class1 是单独的对象,它不是平面对象。在我看来,Base 是 Class2 的模拟,是 Derived (Class1) 的子对象。以上是关于如何从已在其中创建的不同类对象中访问类对象的成员函数?的主要内容,如果未能解决你的问题,请参考以下文章
从 Swift 中的不同类访问 ViewController 中的对象