Jimmy Electron
Jimmy Electron

Reputation: 9

Can a class have a member that is another with the same name in the same namespace?

Suppose I have two classes with the same name in the same namespace in two different files.

This is so I can construct another object with each of the two classes, following the same interface but with some functions that behave differently.

For the differently behaving functions, I will redefine them in one instance of the class.

For the functions behaving the same way, I want to construct an instance of the other class and forward calls.

Is there a way to do this? Clearly I can't have two classes in the same namespace, but perhaps I can redefine the namespace/classname of the class I want to be a member in order to forward calls?

For example:

//file_1.h
namespace x {
 class y {
 }
}

//file_2.h
#include "file_1.h"
namespace x {
  class y {
    // member of same class in the other file
    y memberName;
  }
}

Upvotes: 0

Views: 1473

Answers (3)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275210

Suppose I have two classes with the same name in the same namespace in two different files.

Then you have violated a rule called thd ODR or one definition rule. Doing so makes your program ill-formed, no diagnostic required.

If you have a class Alice that wants tomuse another class Bob, but you want two different definitions for how Bob works, the solutions are called "polymorphism".

Polymorphism is the ability for two or more classes to substitute for one.

There are three simple forms of polymorphism. There is using a virtual interface and runtime polymorphism. There is using templates and compile time pokymorphism. Then there is type erasures via function pointers.

The easiest is defining a virtual interface.

struct IBob {
  virtual int count() const = 0;
  virtual ~IBob() {}
};
struct Alice {
  std::unique_ptr<IBob> my_bob = nullptr;
  void do_stuff() const {
    if(my_bob) std::cout << "Count is:" << my_bob->count() <<"\n";
  }
};

now we can define two implementations of IBob:

struct Bob0:IBob{
  int count() const final { return 7; }
};
struct Bob1:IBob{
  std::unique_ptr<IBob> pBob;
  int count() const final {
    if(pBob) return pBob->count()*2 +1;
    else return 1;
  }
};

now Bob1 has a IBob, and it uses that IBob to implement its own count.

The template way looks like:

template<class Bob>
struct Alice {
  Bob my_bob;
  void do_stuff() const {
    std::cout << "Count is:" << my_bob.count() <<"\n";
  }
};

and the various Bob implementations need no virtual or inheritance. Here you must pick which Bob at compile time at each point of use.

The manual function pointer type erasure solution is more complex. I'd advise against it.

Upvotes: 2

J. Calleja
J. Calleja

Reputation: 4905

You can not modify a class after it has been declared and you can not declare two different classes with the same name.

You can declare a class hierarchy with virtual methods and use a pointer to the base. For example:

class A {
public:
  virtual void f() = 0;
};
class B : public A {
  void f() override {std::cout << "B" << std::endl;}
};
class C : public A {
  void f() override {std::cout << "C" << std::endl;}
};

int main()
{
  A *a1 = new B;
  A *a2 = new C;
  a1->f(); // B
  a2->f(); // C
  return 0;
} 

Although both a1, a2 are pointers to A, the code will print:

B
C

If you do not want to made this class hierarchy public, you can use the pimpl technique. It allows you to hide the real implementation of a class. For example:

// File: A.h
class A {
  class AImpl;
  std::unique_ptr<AImpl> m_pimpl;
public:
  explicit A();
  void f();
};

// File A.cpp
class A::AImpl {
public:
  void f() { std::cout << "A" << std::endl;};
};

A::A() : m_pimpl(new AImpl) {
}

void A::f() {
  m_pimpl->f();
}

Now, you can define inside your cpp file the implementation of class AImpl. You can even use a class hierarchy for AImpl to create different behaving objects depending on the class that you have created internally.

Upvotes: 2

Victor Padureanu
Victor Padureanu

Reputation: 614

When you include a file is like adding the content to that cpp file. So that means you will have the same name for different classes.

There is a possibility to use the same name by using typedef.

class A {
public:
    static void func() {}
};

class B {
public:
    static void func() {}
};

void funcA() {
    typedef A C;
    C::func();
}

void funcB() {
    typedef B C;
    C::func();
}

int main()
{
  funcA();
  funcB();
  return 0;
} 

Upvotes: 0

Related Questions