0

I starts to learn the Multiple Inheritance in C++ and I want to print out the addresses of the class components from the header file.

The original header file defines several classes:

#include <iostream>
#include <iomanip>
class Account
{
  public:
  Account() {}
  unsigned long A1;
};

class Employee : public Account
{
 public:
 Employee() {}
 unsigned long E1;
};
class Student : public Account
{
 public:
 Student() {}
 unsigned long S1;
};
class Work_Study : public Employee, public Student
{
  public:
  Work_Study() {}
  unsigned long W1;
};

The cpp file is below:

Work_Study Obj_WS; // declare a Work_Study object;
Work_Study * Obj_WS_ptr = &Obj_WS; 
int main() {

    std::cout << "Employee Account" << &((Account *) Obj_WS_ptr->A1) << std::endl;
    std::cout << "Employee" << &((Employee *) Obj_WS_ptr->E1) << std::endl;
    std::cout << "Student Account" << &((Account *) Obj_WS_ptr->A1) << std::endl;
    std::cout << "Student" << &((Student *) Obj_WS_ptr->S1) << std::endl;
    std::cout << "Work_Study" << &(Obj_WS_ptr->W1) << std::endl;
    return 0;
 }

There are currently two errors:

The first one is about the ambiguous request for these components.

Test_MI.cpp:12:51: error: request for member ‘A1’ is ambiguous

And with the following note:

note: candidates are: long unsigned int Account::A1 unsigned long A1;

Should I declare the class again in cpp file? Or is there other way?

The other is: lvalue required as unary '&' operand. What does this error means as the components are long unsigned int?

In this multiple inheritance, there are two Accounts for Employee and Student, so if we want to access the Account for Student, we need to cast the pointer to access it because the memory layout is left hand side first with accessing Employee object firstly.

  • 1
    Please show the definition of `Work_Study`. And read about how to create a [mre]. – Paul Sanders May 21 '20 at 23:24
  • The definition is like this: class Work_Study : public Employee, public Student { public: Work_Study() {} unsigned long W1; }; – William Wang May 21 '20 at 23:30
  • Please add that to your question, and please add all the other missing class definitions. In other words, make a [mre]. But ... what's with all the casts? I think you need to do some [background reading](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Paul Sanders May 21 '20 at 23:39
  • I would add the codes from header file. Also, because I think too much codes sometimes would mess people up, so I just post the main source code. I would explain the casts in the post. – William Wang May 21 '20 at 23:44

1 Answers1

0

(Account *) Obj_WS_ptr->A1 is ambiguous because Work_Study has 2 Account instances, and thus 2 A1 members - one inherited from Employee and one inherited from Student. To let the compiler know which Account and thus which A1 you want to access, you would have to either:

  • change your type-cast to use Employee* or Student* instead of Account* (and use static_cast so the casts are easier for you to read and safer for the compiler to parse):
std::cout << "Employee Account" << &(static_cast<Employee*>(Obj_WS_ptr)->A1) << std::endl;
std::cout << "Student Account" << &(static_cast<Student*>(Obj_WS_ptr)->A1) << std::endl;

Live Demo

  • qualify which variable to access without using any type-cast at all:
std::cout << "Employee Account" << &(Obj_WS_ptr->Employee::A1) << std::endl;
std::cout << "Student Account" << &(Obj_WS_ptr->Student::A1) << std::endl;

Live Demo

The alternative is to use virtual inheritance instead:

class Account
{
public:
  Account() {}
  unsigned long A1;
};

class Employee : public virtual Account
{
public:
  Employee() {}
  unsigned long E1;
};

class Student : public virtual Account
{
public:
  Student() {}
  unsigned long S1;
};

class Work_Study : public Employee, public Student
{
public:
  Work_Study() {}
  unsigned long W1;
};

Live Demo

This way, only 1 Account will exist in Work_Study even though Employee and Student both derive from Account, thus solving the so-called "diamond problem" that your classes are creating.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Alright, I get the addresses for the components, thanks a lot. By the way, do you know how to return the address of the casted object pointer? I think these pointers have no address form, so how to use '&' to access? – William Wang May 22 '20 at 00:54
  • I don't understand what you are asking. Please clarify, preferably with an example you are trying to solve. – Remy Lebeau May 22 '20 at 00:57
  • OK, I am trying to return the address value of object pointer under the influence of casting, like: std::cout << "Address of Object Pointer under casting of Employee A1" << &((Employee *)Obj_WS_ptr) << std::endl; – William Wang May 22 '20 at 01:17
  • You don't need to use `&` in that case. The value of the casted pointer as-is is the address you are looking for, eg: `std::cout << "Address of Object Pointer under casting of Employee " << static_cast(Obj_WS_ptr) << std::endl;` You really should start getting in the habit of using C++-style casts instead of C-style casts. [What is the difference between static_cast<> and C style casting?](https://stackoverflow.com/questions/1609163/) – Remy Lebeau May 22 '20 at 01:31
  • The results would be the addresses of the components in class Student and Employee, but I am trying to find the address of the pointer itself. The Pointers have values which are the components' addresses, but what are the Pointers' address? not the content, but the location of pointers. – William Wang May 22 '20 at 01:41
  • I'm not sure why you would ever want to take the address of a casted pointer, that is not useful in any way. Besides, you can't take the address of any temporary value to begin with, you would have to save it to a variable first, but then you would be getting the address of that variable. – Remy Lebeau May 22 '20 at 01:49
  • how about store it in a pointer and return that pointer's value which is the address of the casted pointer? But how to declare this pointer as the casted pointer has casted type – William Wang May 22 '20 at 01:52
  • Again, you can't take the *address* of the result of a type-cast, so you couldn't put the *address* of the casted pointer into another pointer to begin with. All you can store is the *value* of the casted pointer, which is exactly what `cout << (Employee*)Obj_WS_ptr` and `cout << static_cast(Obj_WS_ptr)` print out (since the casted pointer is assigned to a `void*` parameter of `operator<<`). I don't think you are understanding how pointers and type-casts actually work. – Remy Lebeau May 22 '20 at 01:56
  • The previous line cout << &(static_cast(Obj_WS_ptr), which has '&', returns the same value of the line which has same content except '&', should this be? So why '&' has the same effect in this case? – William Wang May 22 '20 at 02:02
  • I have no idea what you are referring to, you are not making any sense. But `&static_cast(Obj_WS_ptr)` is not legal. And the `(` after the `&`, but a missing closing `)` after `Obj_WS_ptr)`, implies you actually copied that from a line that refers to a *member* of the casted `Employee` but you didn't show that completely, such as `&(static_cast(Obj_WS_ptr)->E1)` – Remy Lebeau May 22 '20 at 02:11