0

Inheritance in C++ is specified with the access-specifiers public, protected and private. Private inheritance makes the public and protected members of the base class to become private members of the derived class.

Is there any way of implementing private inheritance in JavaScript?

I know JavaScript has prototype-based inheritance, and so I was confused if there's a way to make the public members of the base class become private members of the derived class.

Bharat Khatri
  • 1,367
  • 2
  • 16
  • 27

3 Answers3

1

This demonstrates C++ style "public", "protected" and "private" data member and member functions.

function Base() {
  'use strict';
  /*--------------------------------------------------------------------------*/
  /*Declare all data members here using 'this.' which makes them 'public', but
  only in the scope of Base.                                                  */
  function Core() {
    this.private_data1 = 'private data1 of Base';
    this.private_data2 = 'private data2 of Base';
    this.protected_data1 = 'protected data1 of Base';
    this.protected_data2 = 'protected data2 of Base';
    this.public_data1 = 'public data1 of Base';
    this.public_data2 = 'public data2 of Base';
  }
  /*--------------------------------------------------------------------------*/
  /*Declare all member function here using 'Core.prototype.' which makes them
  'public' too, but again only in the scope of Base.                          */
  Core.prototype.private_function1 = function() {
    console.log('private function1 of Base.');
  };
  Core.prototype.private_function2 = function() {
    console.log('private function2 of Base.');
  };
  Core.prototype.protected_function1 = function() {
    console.log('protected function1 of Base.');
  };
  Core.prototype.protected_function2 = function() {
    console.log('protected function2 of Base.');
  };
  Core.prototype.public_function1 = function() {
    console.log('public function1 of Base.');
    /*We can call public, protected and private functions ...*/
    this.protected_function1();
    this.private_function1();
    /*... and access public, protected and private from here ...*/
    console.log(this.public_data1);
    console.log(this.protected_data1);
    console.log(this.private_data1);
    /*... even if they're overloaded.*/
    this.public_function2();
    this.protected_function2();
    this.private_function2();
    console.log(this.public_data2);
    console.log(this.protected_data2);
    console.log(this.private_data2);
  };
  Core.prototype.public_function2 = function() {
    console.log('public function2 of Base.');
  };
  /*--------------------------------------------------------------------------*/
  /*Define visibility of the members. If you're editing the core, make sure that
  each member is listed in no more and no less than one of these three
  functions.*/
  Core.prototype.grandPublicAccessTo = function(instance) {
    instance.public_data1 = mCore.public_data1;
    instance.public_data2 = mCore.public_data2;
    instance.public_function1 = function() { mCore.public_function1(); }
    instance.public_function2 = function() { mCore.public_function2(); }
  }
  Core.prototype.grandProtectedAccessTo = function(instance) {
    this.grandPublicAccessTo(instance);
    instance.protected_data1 = mCore.protected_data1;
    instance.protected_data2 = mCore.protected_data2;
    instance.protected_function1 = function() { mCore.protected_function1(); }
    instance.protected_function2 = function() { mCore.protected_function2(); }
  }
  Core.prototype.grandPrivateAccessTo = function(instance) {
    this.grandProtectedAccessTo(instance);
    instance.private_data1 = mCore.private_data1;
    instance.private_data2 = mCore.private_data2;
    instance.private_function1 = function() { mCore.private_function1(); }
    instance.private_function2 = function() { mCore.private_function2(); }
  }
  /*--------------------------------------------------------------------------*/
  var mCore = new Core();

  this.inherit = function(heir, core) {
    /*Grand the base core access to every member of heir's core, and ... */
    core.grandPrivateAccessTo(mCore);
    /*... grand the heir's core access to public and protected members of the
    base's core.*/
    mCore.grandProtectedAccessTo(heir);
  }

  /*Grand public access to every instance of Base.*/
  mCore.grandPublicAccessTo(this);
};

function Child() {
  'use strict';
  /*--------------------------------------------------------------------------*/
  /*Declare a few data members to demonstrate that these mask the corresponding
  members of Base.*/
  function Core() {
    this.private_data2 = 'private data2 of Child';
    this.protected_data2 = 'protected data2 of Child';
    this.public_data2 = 'public data2 of Child';
  }
  /*Overload some member functions to demonstrate that too.*/
  Core.prototype.private_function2 = function() {
    console.log('private function2 of Child.');
  };
  Core.prototype.protected_function2 = function() {
    console.log('protected function2 of Child.');
  };
  Core.prototype.public_function2 = function() {
    console.log('public function2 of Child.');
  };
  /*--------------------------------------------------------------------------*/
  /*Define visibility of the members. If you're editing the core, make sure that
  each member is listed in no more and no less than one of these three
  functions.*/
  Core.prototype.grandPublicAccessTo = function(instance) {
    instance.public_data2 = mCore.public_data2;
    instance.public_function2 = function() { mCore.public_function2(); }
  }
  Core.prototype.grandProtectedAccessTo = function(instance) {
    this.grandPublicAccessTo(instance);
    instance.protected_data2 = mCore.protected_data2;
    instance.protected_function2 = function() { mCore.protected_function2(); }
  }
  Core.prototype.grandPrivateAccessTo = function(instance) {
    this.grandProtectedAccessTo(instance);
    instance.private_data2 = mCore.private_data2;
    instance.private_function2 = function() { mCore.private_function2(); }
  }
  /*--------------------------------------------------------------------------*/
  var mCore = new Core();

  /*Inherit from Base. Multiple inheritance is possible.*/
  var base = new Base();
  base.inherit(this, mCore);

  /*Grand public access to every instance of Child.*/
  mCore.grandPublicAccessTo(this);
};

function main() {
  'use strict';

  console.log('testing base');
  var base = new Base();
  base.public_function1();
  /*Thinks like this:
  base.private_function1();
  would result in a TypeError.*/

  console.log('testing child');
  var child = new Child();
  child.public_function1();
}
main();                                                    

Output:
testing base
public function1 of Base.
protected function1 of Base.
private function1 of Base.
public data1 of Base
protected data1 of Base
private data1 of Base
public function2 of Base.
protected function2 of Base.
private function2 of Base.
public data2 of Base
protected data2 of Base
private data2 of Base
testing child
public function1 of Base.
protected function1 of Base.
private function1 of Base.
public data1 of Base
protected data1 of Base
private data1 of Base
public function2 of Child.
protected function2 of Child.
private function2 of Child.
public data2 of Child
protected data2 of Child
private data2 of Child

p.kamps
  • 86
  • 4
  • In reference to the `inherit` method of `Base`, why do you want to give the base class's core `private` access to the derived class's core, shouldn't the base class be unaware of the classes that derive from it? – Bharat Khatri Apr 01 '14 at 09:37
  • Your solution seems clean, but again we are only dealing with instance properties and so `prototype` based inheritance is not used. Can you tell me the motivation behind introducing a `Core` in every class? I mean every class could, to start with, have every `public` member be exposed directly, and keep every other member intended to be either `private` or `protected` as private variables. Additionally, every class can expose a method that lets other classes have `protected` members of that class exposed to them. – Bharat Khatri Apr 01 '14 at 10:33
  • @Bharat Khatri: The Base uses the derived's core to enable the derived to overload methods of the Base. Without this the last 6 lines of the output would differ. – p.kamps Apr 03 '14 at 10:12
  • @Bharat KhatriL: I made it with this vision: the core holds everything; the object around it, is no more than a defense mechanism. I would like to improve core-core inheritance and standardize the fence such that all class-like object share the same fence. – p.kamps Apr 03 '14 at 10:30
0

The instance properties of the base class are inherited at the point where the derived class constructor calls the base class constructor. At this point, all the instance properties of the base class which need to be inherited privately can be stored as local variables inside the constructor of the derived class and subsequently deleted from the instance of the derived class.

This technique would obviously not work for properties inherited off the prototype of the base class. This, however, served my use case, and hence I'm sharing it here.

In the example below, the derived class ChocolateCake privately inherits the member setBakingTemperature from the base class Cake.

function Cake() {
    var bakingTemperature = 250;
    this.setBakingTemperature = function(temperature) {
        bakingTemperature = Math.min(temperature, 400);
    }
    this.getBakingTemperature = function() {
        return bakingTemperature;      
    }
}

Cake.prototype.bake = function() {
    console.log("Baking the cake at " + this.getBakingTemperature() + " °C");
}

function ChocolateCake() {
    Cake.call(this);

    /* inherit 'setBakingTemperature' privately */
    var setBakingTemperature = this.setBakingTemperature;
    delete this.setBakingTemperature;

    setBakingTemperature(300);
}

ChocolateCake.prototype = Object.create(Cake.prototype, {
    constructor: {value: ChocolateCake}
});


var chocolateCake = new ChocolateCake();
chocolateCake.setBakingTemperature(); /* throws TypeError exception */
chocolateCake.getBakingTemperature(); /* 300 */
chocolateCake.bake(); /* Baking the cake at 300 °C */

Update :

Using @p.kamps idea, there is another way to accomplish this. This approach has the advantage that the child class has the option to choose the properties it wants to inherit from the base class, and doesn't need to care about the other properties.

var Cake = function() {
    var bakingTemperature = 250;
    var setBakingTemperature = function(temperature) {
        bakingTemperature = Math.min(temperature, 400);
    }
    this.inheritSetBakingTemperature = function() {
        if (this instanceof Cake) {
            return setBakingTemperature;
        }
        return null;
    }
    this.getBakingTemperature = function() {
        return bakingTemperature;
    }
}

Cake.prototype.bake = function() {
    console.log("Baking the cake at " + this.getBakingTemperature() + " °C");
}

var ChocolateCake = function() {
    Cake.call(this);

    /* inherit 'setBakingTemperature' privately */
    var setBakingTemperature = this.inheritSetBakingTemperature();

    setBakingTemperature(300);
}

ChocolateCake.prototype = Object.create(Cake.prototype, {
    constructor: {value: ChocolateCake}
});

var chocolateCake = new ChocolateCake();
chocolateCake.setBakingTemperature(); /* throws TypeError exception */
chocolateCake.getBakingTemperature(); /* 300 */
chocolateCake.bake(); /* Baking the cake at 300 °C */
Community
  • 1
  • 1
Bharat Khatri
  • 1,367
  • 2
  • 16
  • 27
-1

Private members of any object in JavaScript are defined in the function that creates the object itself as variables of the function, so those variables will only be visible in the methods of the object that have a reference to the variables, thanks to Clousure.

function Person (age) {
  var age = age;
  this.name = 'Robert';
  this.isAdult = function () {
    return age > 17;
  };
}

In the code above, the age 'property' is private, so private that it actually can't be modified, the only thing you can do with it is checking if it's bigger than 17 with the isAdult method.

Implementing this in a SubClass constructor is pretty much the same thing, you just need to define the property of the prototype you wan't to make private as a variable in the constructor function and define the methods of the object that will have access to that property also in the constructor function.

user3417400
  • 341
  • 2
  • 4
  • Each property of the `prototype` would be publicly accessible through any instance of the subclass. We can't do that with `prototype` properties. – Bharat Khatri Mar 28 '14 at 20:48