Hi guys,
I would like to discuss my design with one query. below is the code snippet.
It is clear from below code snippet that class pd is privately derived from AbstractClass as both are different classes and there is no relation between them.Now in my class pd i need ConcreteClassB's service call to proceed further for my version of do_servicecall function so i have overridden the same. Now if you see the do_servicecall functionimplementation inside pd class then you will realize that through servicecall function(defined in AbstractClass) i am able to overide the implementation provided by ConcreteClassB . Here i can't call do_servicecallfunctional directly as it is declared protected. COuld you suggest if without need of servicecall function same can be achieved. do you think that it is perfect design to implement the same.

    #include <iostream>
    #include<memory>
    #define RESULT_ERROR 0
    #define RESULT_SUCCESS 1
    using namespace std;

    class AbstractClass 
    {
       public:
       int servicecall() //always need this
       { int ret_code;
        ret_code=do_servicecall();
        return ret_code;
       }
        virtual ~AbstractClass(){cout<<"deleting objects";}
        protected:
        virtual int do_servicecall()=0;
    };

    class ConcreteClassA : public AbstractClass 
    {
    public:
      int do_servicecall() {
        cout << "perform service call A " << endl;
        //it will return some value based on success/failure
        return 1; // returning the value based on success/failure
      }

    };

    class ConcreteClassB : public AbstractClass 
    {
    public:
      int do_servicecall() {
        cout << " perform service call  B" << endl;
        //it will return some return type based on success/failure
        // returning the value based on success/failure
        return 2;
      }


    };


    class pd : private AbstractClass 
    {
    int ret_code;   

    public:
    pd(int _ret_code=0):ret_code(_ret_code){}
    int do_servicecall()
    {
    std::unique_ptr<AbstractClass> obj(new ConcreteClassB); 
    ret_code=obj->servicecall();
    //based on ret_code i need to proceed further and call my functionality
    if(ret_code!=RESULT_ERROR)
    {
        //call my function (public to pd class) with return value,suppose it return 3
        ret_code=3;
        return ret_code;
    }

    else
    {

    return RESULT_ERROR;    
    }
    }




    };

    int main()
    { int final_ret_code;
        std::unique_ptr<pd> obj(new pd);
        final_ret_code=obj->do_servicecall();
       cout<<"ret_value="<<final_ret_code;

      return 0;
    }

Recommended Answers

All 9 Replies

hy i am new ,,,i am student of BSCS but i have no practice or grip in C++ ,,,SO PLZ HELP ME

how can we write a program in which we input 10 inputs if the input is character than it store in char array and if we input number than it store in int type and sort array.

class pd is privately derived from AbstractClass as both are different classes and there is no relation between them.

If they are completely unrelated classes, why do you use any kind of inheritance? You should not inherit if there is no purpose to it. In fact, private/protected inheritance is a very peculiar feature that should only very rarely be used, and those uses are kind of "advanced" techniques. Such inheritance is almost never justified in typical C++ code.

And in your case, there seems to be absolutely no purpose for the private inheritance from AbstractClass by the pd class.

COuld you suggest if without need of servicecall function same can be achieved.

No, because that would defeat the point of how the AbstractClass is implemented. The whole point here is that every call to do_servicecall() must go through the non-virtual public member function servicecall() from the AbstractClass. This is a good thing in general because it allows you to encapsulate any implementation details with respect to the relationship between AbstractClass and its derived classes (e.g., shared class invariants, virtual functions, etc.) without affecting the users. The pd class, despite the misleading use of inheritance with AbstractClass, is a class that has no meaningful relationship with AbstractClass nor with any of its derived classes, and therefore, the fact that it is restricted to using AbstractClass' public interface is a good thing.

do you think that it is perfect design to implement the same.

I think that this is a better design:

#include <iostream>

static const int my_result_error = 0;
static const int my_result_success = 1;

class AbstractClass 
{
public:
  int servicecall() {
    return do_servicecall();
  };
  virtual ~AbstractClass(){ 
    std::cout << "deleting objects" << std::endl; 
  };
protected:
  virtual int do_servicecall() = 0;
};

class ConcreteClassA : public AbstractClass 
{
protected:
  int do_servicecall() {
    std::cout << "perform service call A " << std::endl;
    //it will return some value based on success/failure
    return my_result_success;
  };
};

class ConcreteClassB : public AbstractClass 
{
protected:
  int do_servicecall() {
    std::cout << " perform service call  B" << std::endl;
    //it will return some return type based on success/failure
    // returning the value based on success/failure
    return my_result_success;
  };
};


class pd
{
  int ret_code;
public:
  pd(int init_ret_code = 0) : ret_code(init_ret_code) {};

  int do_servicecall()
  {
    ConcreteClassB obj;            // don't use heap for local objects!
    ret_code = obj.servicecall();  // now, this call can be inlined
    //based on ret_code i need to proceed further and call my functionality
    if(ret_code != my_result_error)
    {
      //call my function (public to pd class) with return value,suppose it return 3
      ret_code=3;
      return ret_code;
    }
    else
    {
      return my_result_error;
    }
  };
};

int main()
{ 
  int final_ret_code;
  pd obj;  // again, don't use the heap for local objects!!!
  final_ret_code = obj.do_servicecall();
  std::cout << "ret_value=" << final_ret_code << std::endl;

  return 0;
}

Dear Mike, A very good explanation which is always expected from your end. But still i have doubts in my mind regarding protected virtual function access through private inheritance in unrelated class.As mentioned by scott meyer in effective c++:55 ways to design"we should use private inheritance only if one of the class we want to implement in terms of other class and there is no direct relationship between these two classes and still you want to inherit public/protected virtual function in your class".
Apart from this as hurb sutter stated in "virtually yours" that "virtual function should be always private unless you do have proper reason to declare it protected. if you are providing virtual function implementation in base class and derive class want to call that implementation then it should be protected only." so i believe it should be private only as it doesn't have any implementation. apart from this what do you suggest about composition (passing AbstractClass pointer inside pd class constructor , I have seen composition in my code base a lot.

Below is the implementation which i have seen so far in my code base so far. Please comment/suggest on this.

#include <iostream>

    static const int my_result_error = 0;
    static const int my_result_success = 1;

    class AbstractClass 
    {
    public:
      int servicecall() {
        return do_servicecall();
      };
      virtual ~AbstractClass(){ 
        std::cout << "deleting objects" << std::endl; 
      };
    private: //declared private as it doesn't have any implementation
      virtual int do_servicecall() = 0;
    };

    class ConcreteClassA : public AbstractClass 
    {
    protected:
      int do_servicecall() {
        std::cout << "perform service call A " << std::endl;
        //it will return some value based on success/failure
        return my_result_success;
      };
    };

    class ConcreteClassB : public AbstractClass 
    {
    protected:
      int do_servicecall() {
        std::cout << " perform service call  B" << std::endl;
        //it will return some return type based on success/failure
        // returning the value based on success/failure
        return my_result_success;
      };
    };


    class pd
    {
      int ret_code;
      AbstractClass *obj;
    public:
      pd(AbstractClass *obj,int init_ret_code = 0) : ret_code(init_ret_code),obj(obj) {};

      int do_servicecall()
      {

        ret_code = obj->servicecall(); 
        //based on ret_code i need to proceed further and call my functionality
        if(ret_code != my_result_error)
        {
          //call my function (public to pd class) with return value,suppose it return 3
          ret_code=3;
          return ret_code;
        }
        else
        {
          return my_result_error;
        }


      };
    };

    int main()
    { AbstractClass *obj= new ConcreteClassB ; 
      int final_ret_code;
      pd obj1(obj);  // again, don't use the heap for local objects!!!
      final_ret_code = obj1.do_servicecall();
      std::cout << "ret_value=" << final_ret_code << std::endl;
      delete obj;
      return 0;
    }

As mentioned by scott meyer in effective c++:55 ways to design "we should use private inheritance only if one of the class we want to implement in terms of other class and there is no direct relationship between these two classes and still you want to inherit public/protected virtual function in your class".

I was intrigued by this quote and read that section of Scott Meyers' book. I think you might be taking that "advice" a bit further than it is meant to be taken. And I also have a couple of reservations about it.

First off, the two cases that he describes in that section (which are what I would call "intrusive composition" and EBCO (empty base-class optimization)) are essentially the "advanced" techniques I was referring to in my earlier post (when I said "[private inheritance] should only very rarely be used, and those uses are kind of "advanced" techniques"). So, just understand that his arguments are true in themselves, but they have very small application areas (they are very rarely used). In fact, in modern C++, the EBCO technique, which he describes as an "edge case", is actually far more common today than the other technique he describes. And if you are interested, the reason for that shift in modern times (remember, Effective C++ is quite an old book) is that it's a part of a general tendency to move away from traditional monolithic classes towards much smaller classes (and thus, often empty).

Secondly, as I alluded to already, Effective C++ is quite an old book. I know that the latest edition is from 2005, but remember that a lot of its material comes from Scott Meyers' experiences from the 1990s. The 90s and early 2000s were kind of the "incubation" period for C++. Most would say that modern C++ coding practices were really born in the mid 2000s (2003-2007 or so).

And additionally, Scott Meyers, despite being a great educator and evangelist for C++, he has (1) a very object-oriented mindset and (2) a tendency to sometimes give somewhat bold and not so well "field-tested" advice. The first point is problematic because modern C++ is far less about traditional pure object-oriented programming as it used to be in the 90s, and so, in many cases the advice that Scott Meyers gives tends to neglect alternative non-OOP options that are actually pretty common these days (in many ways, modern C++ was created as a kind of liberation from old-school strict OOP dogma). And the second point is that Meyers is simply not really a professional day-to-day software developer. I guess my point is that Scott Meyers' is just one of those authors you always have to remain a critical thinker about (which is true of all people in one way or another).

So, about the "intrusive composition" case that he was talking about, that uses private inheritance. This is really not common at all. You occasionally see a small form of that in idioms like the non-copyable class idiom (which is somewhat deprecated since C++11 (standard from 2011)). I used to use private inheritance when I wrote GUIs using Qt, because it was one of the main ways that they recommended people should do things, but I eventually had to refactor all my code to avoid it because it interacted badly with the overall compilation process, for reasons that Scott Meyers actually mentions in his book. So, the thing is, this practice can still be seen in old C++ libraries like Qt, OpenInventor, and many GUI libraries, but it's just not part of modern coding practices anymore.

The real problem with private inheritance is that it can have unintended consequences further down the line (like name conflicts with derived class members), and it is generally just too intrusive, and too high of a coupling between the way the two classes (private base-class and its derived class) are implemented, which is not very practical in the long term (especially for maintenance). And finally, these days, people favor small (single-purpose) classes with lots of uses of composition (value data members), which truly diminished the benefits of private inheritance (because there is simply not enough code to be reused to justify reusing it in such a draconian way).

If you want a truly good set of guidelines for OOP class design in C++, refer to "C++ Coding Standards" by Sutter and Alexandrescu. The number one rule in OOP remains: "inherit, not to reuse, but to be reused".

"virtual function should be always private unless you do have proper reason to declare it protected."

I think that Herb Sutter means well by that advice, but I have so often found reasons to go back to the base-class and switch things to being "protected" after originally having made them "private" that I have kind of given up on that "ideal". I find that this rule is not really that important. It's just really rare that you get into trouble because of some misuse of a protected member from a derived class. Especially in today's climate, with small value-semantic classes and "hidden" dynamic polymorphism (best exemplified by Sean Parent's excellent talk on "Inheritance, the base class of all evil", which I think might be a bit too advanced for you, but who knows).

Another part of this argument is that the idea that access rights (public, private, protected) are a way to create encapsulation (of data or implementation details) is kind of debunked now. The reality is that it's too weak for when you need real encapsulation, and it's too annoying when you don't.

apart from this what do you suggest about composition (passing AbstractClass pointer inside pd class constructor , I have seen composition in my code base a lot.

Composition certainly should be first-class citizen in any code-base, that is, it should be the preferred way of doing things. If you are going to use base-class pointers, be sure to think about ownership.

All in all, the lesson you should take out of this is that nothing is black and white and that the journey towards learning to be a good software engineer is full of trade-offs.

good to know your thought and suggestion on this.I forgot to implement the same in terms of modern c++. apart from this when i discussed with my collegues regarding passing raw pointer inside constructor then they were disagree to use unique_ptr in this context by stating that no memory has been allocated through new operator so in this scenario it might not harmful and since 8 year we never ever faced any memory leak issue. so why we should implement using this uniqe_ptr, which anyway is going to be overhead only in current design.Below is the updated code with smart pointer.

#include <iostream>
#include<memory>
static const int my_result_error = 0;
static const int my_result_success = 1;

class AbstractClass 
{
public:
  int servicecall() {
    return do_servicecall();
  };
  virtual ~AbstractClass(){ 
    std::cout << "deleting objects" << std::endl; 
  };
private: //declared private as it doesn't have any implementation
  virtual int do_servicecall() = 0;
};

class ConcreteClassA : public AbstractClass 
{
protected:
  int do_servicecall() {
    std::cout << "perform service call A " << std::endl;
    //it will return some value based on success/failure
    return my_result_success;
  };
};

class ConcreteClassB : public AbstractClass 
{
protected:
  int do_servicecall() {
    std::cout << " perform service call  B" << std::endl;
    //it will return some return type based on success/failure
    // returning the value based on success/failure
    return my_result_success;
  };
};


class pd
{
  int ret_code;
  std::unique_ptr<AbstractClass> obj;
public:
  pd(std::unique_ptr<AbstractClass> obj,int init_ret_code = 0) : ret_code(init_ret_code),obj(std::move(obj)){};   

  int do_servicecall()
  {

    ret_code = obj->servicecall(); 
    //based on ret_code i need to proceed further and call my functionality
    if(ret_code != my_result_error)
    {
      //call my function (public to pd class) with return value,suppose it return 3
      ret_code=3;
      return ret_code;
    }
    else
    {
      return my_result_error;
    }


  };
};

int main()
{ std::unique_ptr<AbstractClass>obj(new ConcreteClassB) ; 
  int final_ret_code;
  pd obj1(std::move(obj));  // again, don't use the heap for local objects!!!
 final_ret_code = obj1.do_servicecall();
 std::cout << "ret_value=" << final_ret_code << std::endl;

  return 0;
}

I would rather stick with C++Primer 5th Ed. Chapter 15, pg. 639-648.
The design pattern works polymorphically and secure through private instantiation of smart pointers.

Dear Mike,
what i understood from scott meyer's comments regarding private inheritance is that: The design you shared here , it indicates that without using any kind of inheritance relationship from AbstractClass to pd class we have overriden the do_servicecall function in pd class, even it wasn't required there . I mean to say instead of overriding do_servicecall function in pd class , we may give that function any other name (other then overriden virtual function name) and execute it.But if it is overriden there then it should have been privately inherited. so point is, does it make sense to overriden the virtual function in unrelated class?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.