Difference Between "Class A; Class B" and "Class A::B"

Difference between class A; class B and class A::B

In Ruby, modules and classes are instances of the Module and Class classes, respectively. They derive their names from the constant they are assigned to. When you write:

class A::B
# ...
end

You are effectively writing:

A::B ||= Class.new do
# ...
end

Which is valid constant assignment syntax, and assumes that the A constant has been properly initialized and that it refers to a Module or a Class.

For example, consider how classes are usually defined:

class A
# ...
end

What is effectively happening is this:

Object::A ||= Class.new do
# ...
end

Now, when you write:

class A
class B
# ...
end
end

What actually happens looks like this:

(Object::A ||= Class.new).class_eval do
(A::B ||= Class.new).class_eval do
# ...
end
end

Here's what is happening, in order:

  1. A new Class instance is asssigned to the A constant of Object, unless it was already initialized.
  2. A new Class instance is asssigned to the B constant of A, unless it was already initialized.

This ensures the existence of all outer classes before attempting to define any inner classes.

There is also a change in scope, which allows you to directly access A's constants. Compare:

class A
MESSAGE = "I'm here!"
end

# Scope of Object
class A::B
# Scope of B
puts MESSAGE # NameError: uninitialized constant A::B::MESSAGE
end

# Scope of Object
class A
# Scope of A
class B
# Scope of B
puts MESSAGE # I'm here!
end
end

According to this blog post, the Ruby core team calls the "current class" the cref. Unfortunately, the author does not elaborate, but as he notes, it is separate from the context of self.


As explained here, the cref is a linked list that represents the nesting of modules at some point in time.

The current cref is used for constant and class variable lookup and
for def, undef and alias.


As the others have stated, they are different ways of expressing the same thing.

There is, however, a subtle difference. When you write class A::B, you assume that the A class has already been defined. If it has not, you will get a NameError and B will not be defined at all.

Writing properly nested modules:

class A
class B
end
end

Ensures the A class exists before attempting to define B.

What is the difference between class A : BC and class AT : BT where T : C?

Say you had a class

public class D : C
{
}

Then in your first example the below is valid.

var a = new A<D>

You can use any class for T that is ultimately derived from C.

Whereas your second code is hard coded to have B use C for the genric type parameter and is not generic.

Inheritance Class different between ' class a : b ' And ' class a : public b '

class b: public a{/*..*/};

b inherits from a publicly (i.e) all of the member functions and vars are inherited in b with the same access specifiers they have in a

class b: a{/*..*/};

b inherits from a privately (i.e) all of the member functions and vars are inherited in b with private access specifiers.
So you can't access your function eatFunction outside the class.

Variable of class A in class B and pointer of class B in class A?

You need to declare A before you define B:

class A;   // declaration of A

class B // definition of B
{
A* foo;
// ...
};

class A // definition of A
{
B bar;
// ...
};

This kind of declaration is often referred to as a forward declaration.

class B inside class A inherits class A

This can be done, but the definition of B needs to be moved outside of A. Until the closing brace, A is an incomplete type, whereas the base class must be complete.

This would work:

class A {
class B;
};

class A::B : public A {
using A::A;
};

Relation between class A and class B

It's just an nested class i.e. class within class. It's similar to you defining field and passing value like say private String mystr = new String(str); So here you can access private field str and pass it onto String.

Similarly you have defined non static class within the outer class which would access private/protected/public field defined in outer class.

You call a class as derived, if say it extends another class. Something like:

public class MyParentClass {}
public class MySubClass extends MyParentClass {}

C++ : class A reference classe B (in a vector) and class B reference A (only one)

Q1. When declaring a vector<Animal> the Animal class has to be a complete class. Unlike Java, C++ stores the member elements by value and not by reference.

Q2 & Q3. Zoo z(); declares a function taking no parameters and returning a Zoo. So you try to use a function name in the constructor of Animal. Doesn't work.

Q4. Creating a temporary parameter works, provided the addAnimal takes a const reference to the parameter - void addAnimal(Animal const& a);.

And, easy on the getters! Returning a copy (cloning?) of all the animals from the Zoo seems a bit much. What is the use of getAnimals, other than creating a new zoo?

Also, real animals at a zoo generally don't know which zoo they belong to. So having a reference in the Animal object seems a bit odd.

Also (2), std::vector<Animal> animals(); is another function declaration, just like Zoo z();. You have to watch out for those.

What is the difference between Type and Class?

The following answer is from Gof book (Design Patterns)

An object's class defines how the
object is implemented. The class
defines object's internal state and
the implementation of its
operations.

In contrast, an object's
type only refers to its interface - a
set of requests to which it can
respond.

An object can have many types,
and objects of different classes can
have the same type.

//example in c++
template<typename T>
const T & max(T const &a,T const &b)
{
return a>b?a:b; //> operator of the type is used for comparison
}

max function requires a type with operation > with its own type as one of it interface any class that satisfies the above requirement can be used to generate specific max<particular class/primitive type> function for that class.

Class A needs class B that needs class A and all its members

But given I need to access a number of those dozens of functions (In one way and in the another), is there any way I can avoid using forward declaration?

I am not sure you understand what the forward declaration does. You only need to provide one forward declaration in window.hpp for Console, and then include console.hpp from window.cpp.

Class C inherits Class B and Class A. Class B also inherits Class A

You can use virtual inheritance like shown in the answer of Sam Cristall, but that will make only one Logger object in an instance of C, with the side effect that the log will not output the correct name (you also found this problem in a comment of this answer).

Composition

One solution would be to use composition instead of inheritance:

class B
{
private:
Logger log;
// ...
};

Probably the simplest solution. You can see a live example here.

Inheritance

Another solution is to make the base classes different, here by using CRTP. That is:

template<typename T>
class LoggerImp : public Logger
{
public:
LoggerImp(const std::string& n) : Logger(n) {}
};

class B : private LoggerImp<B>
{
private:
typedef LoggerImp<B> LL;

public:
B() : LoggerImp<B>("Class B" ) {}

void doSomethingInB()
{
LL::log("B doing something");
}
};

class C : public B, private LoggerImp<C>
{
private:
typedef LoggerImp<C> LL;

public:
C() : LoggerImp<C>("Class C" ) {}

void doSomethingInC()
{
LL::log("C doing something");
}
};

Some notes:

  • I used private inheritance because as I understand your problem the logger is useful only to B or C, not owner of these objects.
  • The CRTP is used to disambiguate the base names. It is not sufficient but help a lot in your problem
  • The typedef is for readability. The fact that the logger bases have different names allows to correctly typedef them, permitting us to call the correct log function.
  • A typedef in a derived class hides a typedef in the base class (provided they're for the same name). So you can use the same code for logging in different classes.
  • You can also make the Logger class directly a CRTP.
  • You can see a live example here.


Related Topics



Leave a reply



Submit