assume the following class is given:
class Base{
public:
Base() {}
Base( const Base& b) : base_attr(b.base_attr) {}
void someBaseFunction()
{ .... }
protected:
SomeType base_attr;
};
When I want a class to inherit from this one and include a new attribute for the derived class, I would write:
class Derived: public Base {
public:
Derived() {}
Derived( const Derived& d ) : derived_attr(d.derived_attr)
{
this->base_attr = d.base_attr;
}
void SomeDerivedFunction()
{ .... }
private:
SomeOtherType derived_attr;
};
This works for me (let's ignore eventually missing semicolons or such please).
However, when I remove the "this->" in the copy constructor of the derived class, the compiler complains that "'base_attr' was not declared in this scope".
I thought that, when inheriting from a class, the protected attributes would then also be accessible directly. I did not know that the "this->" pointer was needed.
I am now confused if it is actually correct what I am doing there, especially the copy-constructor of the Derived-class.
Because each Derived object is supposed to have a base_attr and a derived_attr and they obviously need to be initialized/set correctly.
And because Derived is inheriting from Base, I don't want to explicitly include an attribute named "base_attr" in the Derived-class. IMHO doing so would generally destroy the idea behind inheritance, as everything would have to be defined again.
EDIT
Thank you all for the quick answers. I completely forgot the fact that the classes actually are templates.
Please, see the new examples below, which are actually compiling when including "this->" and are failing when omiting "this->" in the copy-constructor of the Derived-class:
Base-class:
#include <iostream>
template<class T>
class Base{
public:
Base() : base_attr(0) {}
Base( const Base& b) : base_attr(b.base_attr) {}
void baseIncrement()
{ ++base_attr; }
void printAttr()
{
std::cout << "Base Attribute: " << base_attr << std::endl;
}
protected:
T base_attr;
};
Derived-class:
#include "base.hpp"
template< class T >
class Derived: public Base<T>{
public:
Derived() : derived_attr(1) {}
Derived( const Derived& d) : derived_attr(d.derived_attr) {
this->base_attr = d.base_attr;
}
void derivedIncrement()
{ ++derived_attr; }
protected:
T derived_attr;
};
and for completeness also the main function:
#include "derived.hpp"
int main()
{
Derived<int> d;
d.printAttr();
d.baseIncrement();
d.printAttr();
Derived<int> d2(d);
d2.printAttr();
return 0;
};
I am using g++-4.3.4.
Although I understood now that it seems to come from the fact that I use template-class definitions, I did not quite understand what is causing the problem when using templates and why it works when not using templates. Could someone please further clarify this?
You are only seeing this if Base in some way depends on template arguments.
In that case, it's deemed too dangerous that a name like base_attr is lookup up in such a dependent base class: For some template instantiation, the name could be found in the base class, and for another instantiation, the member could be absent and the name would refer to a some namespace member.
Because this was thought to be confusing, C++ follows the consistent rule that base_attr is never lookup in a dependent base class when doing unqualified name lookup. You need to prefix the name with this-> or with the name of the class as in Derived<T>::base_attr. So when the base class doesn't declare a base_attr, the name doesn't silently refer to a potentially globally declared name, but it will just be a compile time error.
There is no reason that this should be necessary. All member variables are implicitly accessed through this-> and I know of no language rules that specify that you should need to use this-> to access any member functions or variables.
I don't know why you're getting that error without seeing a compilable example, but you can write your copy constructor thus:
Derived( const Derived& d ) : Base(d.base_attr), derived_attr(d.derived_attr) {}
What compiler are you using? I'm not getting any error with g++ and nor do I see anything wrong with the code you have listed.
Related
This question already has an answer here:
Why does having a declaration of a private base class render a type name inaccessible?
(1 answer)
Closed 1 year ago.
I ran into a problem, that I somehow managed to solve, but still would like to understand the language and the reasoning behind it. I have the following system of three classes:
File class_a.hpp
#pragma once
class A
{
public:
A();
};
File class_b.hpp
#pragma once
#include "class_a.hpp"
class B : A
{
public:
B() : A() {}
virtual double do_something(A &with_object) const;
};
File class_c.hpp
#pragma once
#include "class_b.hpp"
class C : B
{
public:
C() : B() {}
double do_something(::A &with_object) const; // but differently than class B
};
Now if I was not to use the fully qualified name for the type A in the C's do_something() method, I'd get the following error still in editor:
type "A::A" (declared at line 27 of "class_a.hpp") is inaccessible C/C++(265)
What could be possible causing any ambiguity in this case? I certainly haven't redefined or used the name A as an identifier. Is there something happening in the background that makes use of the class name?
Also is the override of the do_something() method guaranteed to work this way, or is qualifying the type A in the B's method also required?
Any advice and/or pointers are also greatly appreciated!
Among other things that are inherited, there are injected-class-names. You can think of them as of hidden type aliases: class A has something like using A = A; in it, pointing to itself.
And remember that class inheritance is private by default.
Since B inherits from A privately, C can't access the contents of A, which includes A's injected-class-name.
Also is the override of the do_something() method guaranteed to work this way, or is qualifying the type A in the B's method also required?
Yes, the override in B is valid. Since B inherits from A directly, it can access all its contents, regardless of whether the inheritance is private or not.
Your code is similar to following. I replaced the injected-class-name with an actual type alias, and got the same behavior.
class A
{
public:
using A_type = A;
};
class B : A
{
public:
virtual double do_something(A_type &with_object) const;
};
class C : B
{
public:
double do_something(A_type &with_object) const;
};
I've looked at over a dozen qst's with the phrase no appropriate default constructor available in it but none help with my own problem.
It's a very basic C++ qst (as I'm still learning the ropes), so sorry in advance if your eyes are glazing over at it's simplicity. I am trying to inherit a class that has a templated constructor with no arguments. Such as:
class Base {
public:
template<class T>
Base() {
T *t = this;
//more irrelevant stuff
}
}
I've tried
class Derived : public Base {
public:
Derived() : Base() {
}
}
and
class Derived : public Base {
public:
Derived() {
}
}
to no avail. In both cases I get the error message no appropriate default constructor available . How to go about doing this? If this is not possible can you explain why?
It worked when I set up my constructor like template<class T> Base(T *t) (taking the template argument as a parameter).
p.s. In case it matters, in my code I am also inheriting Derived by another class.
there is no syntax for accessing the default constructor in
class blah_t
{
public:
template< class other_t > blah_t() {}
};
there also some other ways to make the default constructor inaccessible, e.g.
class blah_t
{
public:
blah_t() {}
blah_t( int = 666 ) {}
};
as the holy standard explains it, constructors don't have names…
but, back to the original question, in order to be able to specify the template argument, you need some ordinary function argument that involves the template parameter type
i have an inheritance struct A : public B, i want to hide individual functions from B, is this possible?
i know the opposite is possible using using BMethod in the A declaration.
cheers
If you want to selectively hide functions from B it does not make much sense to use public inheritance in the first place.
Use private inheritance & selectively bring methods from B into the scope of A:
struct B{
void method1(){};
void method2(){};
};
struct A : private B{
using B::method1;
};
A a;
a.method1();
a.method2(); //error method2 is not accesible
There is an issue here: this would be a direct violation of the Liskov Substitution Principle, namely A would not act as a B any longer.
If you wish to reuse B implementation, the solution is simply to do so:
class A
{
public:
void foo() { return b.foo(); }
void bar() { return b.bar(); }
// ...
private:
B b;
};
Don't abuse inheritance, use composition instead
The using keyword can be used to change visibility
struct A
{
void method1();
};
struct B: public A
{
void method2();
private:
using A::method1;
};
Aside from the ways described in the previous answers—composition, private inheritance, and non-private inheritance but with the inherited method declared private—another way is to explicitly delete the inherited method:
#include <iostream>
struct A {
void foo() { std::cout << "foo\n"; }
};
struct B : A {
void foo() = delete;
};
int main() {
B b;
b.foo(); // COMPILER ERROR
}
Although the b.foo() call produces a compiler error, client code can still call the base class’s version by qualifying with the base class identifier A:
b.A::foo(); // compiles, outputs 'foo' to console
This explicit deletion way works when foo is not a virtual non-deleted method in A. By C++11 Standard §10.3/16, this explicit deletion is ill-formed when the deleted method in the derived class overrides a virtual non-deleted method of the base class. For more info on this restriction, see the answers to the SO question C++11 Delete Overriden Method.
You can't "hide it" per se, but you can make it a compile time error to call it. Example:
struct A
{
void AMethod() {}
};
class B : public A
{
void AMethod() {} //Hides A::AMethod
};
int main()
{
B myB;
myB.AMethod(); //Error: AMethod is private
static_cast<A*>(&myB)->AMethod(); //Ok
return 0;
}
Examples on codepad with the error, and without.
That all said, despite this being possible, you really shouldn't do it. You'll confuse the hell out of clients.
EDIT: Note that you can also do this with virtual functions (And with the error).
To those that are suggesting composition... this might not be the best possible way of going about things. My understanding is that the Liskov Substitution Principle only states that there's the possibility of the functions from the base class being used on the child, not that they necessarily should be. For example, for a particular base class you may have multiple functions that essentially perform the same operation, but for different specific cases. In the derived class you may want to abstract these public functions away in favor of simplifying the user's interface. This is where private inheritance can be used. Private inheritance might also be a necessity, if we have protected functions in the base class that we don't want the user of the base class to call, yet would be invaluable to the derived class.
In short, if you HAVE to, use private inheritance, but composition is preferred in most cases.
There is yet another approach.
class A{
void f1();
void f2();
void f3();
}
class BInterface{
void f2();
void f3();
}
class B : public A, BInterface
{
}
BInterface b = new B();
b->f1(); //doesn't work since f1 is not declared in BInterface
b->f2(); //should work
b->f3(); //should work
delete(b);
Use BInterface as a filter for inherited classes to exclude undesirable methods. Liskov Substitution principle isn't violated in this case since an object of BInterface class is not an object of A class even though that an object of B class is an object of BInterface class.
If the methods are private in B, then they will remain hidden to a even if you use public inheritance.
Can't alter the visibility of the original method.
You could create a method in struct A with the same name and have that method be private, but that doesn't prevent the method from being called when an instance of struct A is being referenced by a variable of type B.
Why don't you make it Virtual in the base class and override it in its Children? (more help)
Let's say I have the following class hierarchy:
class Base
{
protected:
virtual void foo() = 0;
friend class Other;
};
class Derived : public Base
{
protected:
void foo() { /* Some implementation */ };
};
class Other
{
public:
void bar()
{
Derived* a = new Derived();
a->foo(); // Compiler error: foo() is protected within this context
};
};
I guess I could change it too a->Base::foo() but since foo() is pure virtual in the Base class, the call will result in calling Derived::foo() anyway.
However, the compiler seems to refuse a->foo(). I guess it is logical, but I can't really understand why. Am I missing something ? Can't (shouldn't) it handle this special case ?
Thank you.
When you qualify a method name with a class name, as in Base::foo() dynamic dispatch (run-time binding) does not apply. It will always call the Base implementation of foo(), no matter if foo() is virtual or not. Since in this case it is pure virtual, there is no implementation and the compiler complains.
Your second problem is that in C++, friendship is not inherited. If you want Other to have special access to Derived, it needs to be a friend of Derived specifically.
This, on the other hand, works:
Base* a = new Derived();
a->foo();
Because here, you are calling foo() on a Base* where foo() is public, and since you are not qualifying foo() with a class name, it uses dynamic dispatch and ends up calling the Derived version of Foo.
I guess You could do this
void bar()
{
Base* a = new Derived();
a->foo();
};
However, the compiler seems to refuse that.
Refuse what? It sounds like you are saying that the compiler is refusing to allow Other to call the foo() function through a Base pointer. That certainly shouldn't be the case.
To answer your basic question, friendship is not inherited....period. Permission scope is checked at the same stage as name resolution and since foo() is protected within the names you are using, you can't call it.
Polymorphism on the other hand is resolved through pointer redirection and has nothing to do with name resolution or access permission.
Try put this "friend class Other;" in the derived class.
Update: Now think of it, I agree with Tyler that you should change a to a Base pointer.
Base* a = new Derived();
It's unfortunate, but friendliness is inherently broken in C++ in my opinion:
Not inherited
Give unrestricted access to all the internals, no possibility to restrict it
I've given up using it "as-is" and I now mostly use the Key pattern (for lack of a better name).
///
/// Key definition
///
class Friend;
class FriendKey: boost::noncopyable { friend class Friend; FriendKey() {} };
///
/// Base/Derived definition
///
class Base
{
public:
void mySpecialMethod(const FriendKey&) { this->mySpecialMethodImpl(); }
private:
virtual void mySpecialMethodImpl() = 0;
}; // class Base
class Derived: public Base
{
public:
private:
virtual void mySpecialMethodImpl() {}
}; // class Derived
///
/// Friend definition
///
class Friend
{
public:
void mySpecialCall()
{
Derived d;
d.mySpecialMethod(FriendKey());
}
}; // class Friend
The concept is simple: each class declares a key (possible even in the forward header), and those that wish to grant special access to them will only make it possible for this key.
It's not perfect, because you can of course abuse it (by transitivity of the key). But then in C++ you can abuse everything, so it's more a problem of protected against Murphy than Machiavelli.
Is the following valid? Or how can I get something close to this.
template<class T_> class Template {
//something
};
class Parent {
public:
Template<Parent> variable;
Parent() : variable(this) { }
};
class Derived : public Parent {
public:
Template<Derived> variable;
Derived() : Parent() { }
}
Thanks in advance.
It's technically "valid" in that your compiler has to accept it (it may warn you, and IMHO it should), but it doesn't do what you think it does: Derived's variable is separate from Parent's, and is not getting explicitly initialized (so it uses the default ctor for Template<>).
If you want to have a variable with the same name in a base and derived class you don't need templates.
Just define them and from derived access ->variable and ->Base::variable. Those are 2 different variables.
Few minor types.
But the main problem was that Parent was using a constructor on Template that did not exist.
template<class T>
class Template
{
public:
Template() {} // Used in Derived
Template(T* t) {} // Used in Parent
};
class Parent
{
public:
Template<Parent> variable;
Parent() : variable(this) {}
};
class Derived : public Parent
{
public:
Template<Derived> variable;
Derived() : Parent() {}
};
I am curious what you are trying to achieve though.
Is this some variation of the "Curiously Reoccurring Template" Pattern or something?
You shouldn't get something close to this, because such a redefinition of a public variable violates Liskov Substitution Principle - your Derived becomes more restrictive than Parent, and cannot be substituted in its place, and therefore it shouldn't be in a superclass/subclass relation.
Furthermore, if it would allow you to redefine a field in a sense of actually reusing the same memory location somehow, then it would break the type system as well: all methods in Parent expect variable to be of type Template<Parent>; if it actually be an instance of Template<Derived>, there is no guarantee that Template<T> is covariant in T.