简体   繁体   中英

C++ Can a class pass itself by reference?

Trying to pass a parent class object to a child class object so that the child class object has control over the parent class object's methods.

This is however resulting in header related issues. I've tried forward declaring one of the classes but it seems whatever class is declared first always has trouble reading from the class declared below.

Both errors refer to Device' constructor where try to call dm's hello world method, they are:

Use of undefined type 'DeviceManager'
Left of '->HelloWorld' must point to class/struct/union/generic type

...

//main.cpp
#include "parent.h"

void main()
{
    cout << "Created DeviceManager\n";
    DeviceManager* deviceManager = 0;
    deviceManager = new DeviceManager;

    cout << "Giving  DeviceManager a device\n";
    deviceManager->p = new Device(deviceManager);

    cout << "Giving  Device a reference to DevicenManager\n";
    deviceManager->Share();
}

...

class DeviceManager;
class Device
{
public:
    Device(DeviceManager* manager)
    {
              dm = 0;
        this->dm = manager;
        this->dm->HelloWorld();
    }

    DeviceManager* dm;
};

//device manager
class DeviceManager
{
public:
    DeviceManager()
    {
        p = 0;
    }
    void HelloWorld()
    {
        //if this calls we know the child has control over the parent.
        cout << "Hello World";
    }

    Device* p;
};

Yes.

To solve circular dependencies with class member and function declarations, you can forward-declare a class:

class A;

class B {
        A *a;
};

class A {
        B *b;
};

To define class member functions that access members of the other class, you must define the function after the other class has been defined:

class B;

class A {
public:
        void f(B &arg);
};

class B {
public:
        void g(A &arg);
};

void A::f(B &arg) {
        arg.g(*this);
}

void B::g(A &arg) {
        arg.f(*this);
}

Usually, in a C++ project, you wouldn't even encounter this problem: You would put function definitions, ie implementations, into .cpp files, while putting the class definitions into header files. Class forward declarations, if neccesary, could be put into their own header files that are included by all headers that need them.

A full example of how you would split the above code into multiple files:

a.cpp

#include "a.h"

#include "b.h"

void A::f(B &arg) {
    arg.g(*this);
}

b.cpp

#include "b.h"

#include "a.h"

void B::g(A &arg) {
    arg.f(*this);
}

ah

#ifndef _A_H_
#define _A_H_

#include "forward_declarations.h"

class A {
public:
    void f(B &arg);
};

#endif //_A_H_

bh

#ifndef _B_H_
#define _B_H_

#include "forward_declarations.h"

class B {
public:
    void g(A &arg);
};

#endif //_B_H_

forward_declarations.h

#ifndef _FORWARD_DECLARATIONS_H_
#define _FORWARD_DECLARATIONS_H_

class A;
class B;

#endif //_FORWARD_DECLARATIONS_H_

As a general rule of thumb, if you need to forward-declare a class, you might have misdesigned something and should think about whether there is a better way (but there also are perfectly valid use cases that require class forward declarations).

If you don't understand my #ifndef , #define and #endif preprocessor lines: These are header guards, and should be used with all files that are included somewhere else, exception you know precisely what you're doing. Believe me. You'll regret ommiting one.

If your problem is cyclic dependancy, like this:

// DeviceManager.h
#include "device.h"
class DeviceManager
{
    DeviceManager(Device& device) {}
};

// Device.h
#include "DeviceManager.h"
class Device
{
    Device(DeviceManager& manager) {}
};

You can solve the problem be forward declaring one of the classes, and passing the object by pointer.

// Device.h
//#include "DeviceManager.h"
class DeviceManager;
class Device
{
    Device(DeviceManager* manager) {}
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM