SPMP
SPMP

Reputation: 1223

Private inheritance and implicit conversion

I have a class that inherits privately from std::string, and adds some functions. I want to be able to use this class just like std::string, so I am trying to define an implicit conversion operator (operator string()). However, I keep getting inaccessible base error.

#include <iostream>
#include <string>

using namespace std;
class Test:private string {
    int _a;
    public:
    operator string() {
        return "hello";
    }
};

int main() {
    Test t;
    if(t == "hello") {
        cout<<"world\n";
    }
}

Error:

trial.cpp: In function ‘int main()’:
trial.cpp:15:13: error: ‘std::basic_string<char>’ is an inaccessible base of ‘Test’
 if(t == "hello") {
         ^

Questions:

  1. Is it a bad idea to define such a conversion? Does this break any recommended programming practices?
  2. How can I make this work?

EDIT: Clang was more helpful

trial.cpp:8:5: warning: conversion function converting 'Test' to its base class 'std::basic_string<char>' will never be used
    operator string() {
    ^
trial.cpp:15:8: error: cannot cast 'Test' to its private base class 'basic_string<char, std::char_traits<char>, std::allocator<char> >'
    if(t == "hello") {
       ^
trial.cpp:5:12: note: declared private here
class Test:private string {
       ^~~~~~~~~~~~~~

Upvotes: 9

Views: 2484

Answers (3)

David G
David G

Reputation: 96845

A conversion function to a private base class defeats the purpose of private inheritance. That's part of the reason why the standard forbids this kind of behavior:

A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void.

If you want access to the base class you should make the inheritance public. This keeps the code readable and comprehensive for others who may have to maintain it.

Upvotes: 5

Weak to Enuma Elish
Weak to Enuma Elish

Reputation: 4637

There are two ways I know to do it that suck, but still work. It isn't really implicit, though...

The less terrible way is explicitly calling the operator:

if(t.operator string() == "hello")

The more terrible way is a c-style cast.

if (*(string*)&t == "hello")

Note that this performs a static_cast to the base class pointer, not its evil sibling the reinterpret_cast.

From the cppreference on explicit cast:

pointer or reference to a derived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class is inaccessible

Upvotes: 2

TheOperator
TheOperator

Reputation: 6506

  1. Is it a bad idea to define such a conversion? Does this break any recommended programming practices?

Yes, inheriting a class that was not designed for it is generally a bad idea. It seems like the approach ("inherit") to your problem ("add some functions") originates from other programming languages where inheritance is common practice, for example Java.

In C++ where you have value semantics and an entire range of powerful abstraction mechanisms, inheritance often creates more problems than it solves, because some functions may not be virtual, and in order to store the object polymorphically, you must use dynamic allocation.

How can I make this work?

Is there a reason why you don't use the standard C++ way -- global functions? They have a lot of advantages: they can be added without changing the class and without forcing users to use a different class (your derived one) and they increase encapsulation by limiting the number of member functions (which have direct access to the class internals).

Upvotes: 1

Related Questions