Consider the following code:
#include <iostream>
class Base{
public:
int iB;
Base() :iB(0){};
virtual ~Base(){}
virtual void foo(Base&, const int&, const int&) const = 0;
};
class Derived : public Base{
public:
int iD;
Derived() :iD(1){};
void foo(Derived&, const int&, const int&) const;
};
void Derived::foo(Derived& d, const int& i1, const int& i2) const{
std::cout << d.iD;
}
class BaseWrap{
public:
BaseWrap(){};
virtual ~BaseWrap(){};
virtual Base* bar() const = 0;
protected:
Base* b;
};
class DerivedWrap : public BaseWrap{
public:
DerivedWrap(){};
Derived* bar() const;
private:
Derived* d;
};
Derived* DerivedWrap::bar() const {
return new Derived;
}
int main(){
return 0;
}
This results in a compiler error "Error: object of abstract class type "Derived is not allowed" pure virtual function Base::foo" has no overrider.
I assumed that thanks to polymorphism I can always put a pointer to a derived class where a pointer to Base class is expected. Anyway, I tried changing the Derived class to the below:
class Derived : public Base{
public:
int iD;
Derived() :iD(1){};
void foo(Base&, const int&, const int&) const;
};
void Derived::foo(Base& d, const int& i1, const int& i2) const{
std::cout << d.iD;
}
However, now I I get the error "Error: class "Base" has no member "iD".
EDIT:
foo takes a ref to derived because in my real implementation i.e. I want to be able to do this:
Derived d1;
Derived d2;
d1.foo(d2, 0, 1);
Furthermore, I probably should have been more clear on what I am actually asking. I realize that removing the pure virtual function declatation
virtual void foo(Base&, const int&, const int&) const = 0;
fixes the issue. However, in all derived class implementation the code is exactly the same, and only varies in the type of the first argument (derived classes from Base). So it feels like there should be a pure virtual function to enforce existence of foo.
The problem
In your base class you define the pure virtual member function:
virtual void foo(Base&, const int&, const int&) const = 0;
but you provide in the derived a function with another signature:
void foo(Derived&, const int&, const int&) const;
So you have one more member function in the derived class (an overload: same name but different parameter types), but still the inherit the pure virtual function. So the derived class is as abstract as the base class and you're not allowed to instantiate it.
The solution
In the derived class change the signature so that it matches the pure virtual bas e member function:
void foo(Base&, const int&, const int&) const;
By the way, whenever you use virtual functions, use override keyword to spot these kind of subtle errors at compilation, even for ordinary virtual functions:
void foo(Base&, const int&, const int&) const override;
More infos
Indeed, once you define your foo() with a Base parameter, you can't use easily the iD member.
The first solution is to use a dynamic_cast to tell your code that the base is in fact a derived object. Of course you have to check if this assumption is correct:
void Derived::foo(Base& d, const int& i1, const int& i2) const{
Derived *dp = dynamic_cast<Derived*>(&d);
if (dp) {
std::cout << dp->iD;
}
}
However, what is not clear to me is why you need this first in a first place. Why not get rid of this first type dependent parameter and use the member variables of the current object:
void Derived::foo(const int& i1, const int& i2) const{
std::cout << iD;
}
Eventually, I came accross this : What are the differences between a pointer variable and a reference variable in C++?
I conclude that since :
A reference cannot be re-bound, and must be bound at initialization, then the line :
rBase = rDeriv;
only triggers stBase copy operator, it does'nt rebind rBase.
A reference can be seen as an alias to a typed variable => no polymorphism is possible through a reference.
Related
In my specific case, I have a base class 'Base', with a data member 'A_var'. I'd like that any derived classes only have const access to that data member, in a syntactically equal fashion to the 'Base' class.
If it's protected or private, then derived classes have full or no access, respectively. I could make it private, and make a protected function that returns a const reference, but then the access would be syntactically different.
class Base {
protected:
const type_t& A() const {return A_var;}
private:
type_t A_var;
void f();
};
class Derived : public Base{
public:
void g();
};
//access in Base class
void Base::f() {
type_t value = A_var;
A_var = value;
}
//access in Derived class
void Derived::g() {
type_t value = A();
A() = value; //Error, const reference; good
}
Overloading 'A()', as below, also doesn't work, because the 'Derived' class calls the private non-const 'A()'.
protected:
const type_t& A() const {return A_var;}
private:
type_t& A() {return A_var;}
The small difference may not seem like a big deal, but in my code there are various macros that start with access to that data member. As such, I have to have different macros for the 'Base' class and derived classes, which disrupts the flow of the code, both reading and writing.
Update:
To clarify, the issue is one of making the access in the derived and base classes the same, syntactically. That is, for instance, that I could call a function f(), and have it return a non-const reference when called in the base class, but a const reference when called in a derived class. The motivation is to make the forced const access in derived classes seamless. I realize there may not be a way to do this, but I asked just in case.
Update:
To present a real example (there are 2-3 of such cases), this is used a lot in the code:
test_files_var.current()->current_test()
I replaced that with a
#define TEST() test_files_var.current()->current_test()
because the derived class would access test_files_var through a different function/member, i.e. testFiles(), I have to have a second definition of TEST(), i.e. DTEST(). The problem is given more by the number of times the 'macros' are used, than by how many of them there are.
Where is no simple built-in solution.
But a bit of template magic can probably do a trick:
template <class NonConst>
struct Matcher {
template <class AnyOther>
static const AnyOther &get(AnyOther &obj) { return obj; }
static NonConst &get(NonConst &obj) { return obj; }
};
class Base {
public:
Base() : a_(42) { }
public:
virtual void Fun() {
Matcher<Base>::get(*this).A();
}
const int &A() const {
std::cout << "const" << std::endl;
return a_;
}
int &A() {
std::cout << "no const" << std::endl;
return a_;
}
private:
int a_;
};
class Derived : public Base {
public:
void Fun() {
Matcher<Base>::get(*this).A();
}
};
int main(int argc, const char * argv[]) {
Derived d;
d.Fun();
Base b;
b.Fun();
return 0;
}
The code above will output: const no const.
So in both Fun functions you have essentially the same access pattern which you could wrap in a macros if you need.
If I understand your question correctly, you want to give access to the derived classes access to a private variable of the base class but in read only.
In this case, you just have to define a protected constant reference variable and intialize it to the private variable:
class Base {
public:
Base() : cA(A_var) { ... } // to be completed with rule of 3
protected:
const type_t& cA;
private:
type_t A_var;
void f();
};
The access in the derived class uses then the constant reference:
//access in Derived class
void Derived::g() {
type_t value = cA;
//cA = value; //Error, const reference: can't assign
}
Live demo
You may change your Base class to
class Base {
public:
Base() : A_cref(A_var) {}
private:
type_t A_var;
void f();
protected:
const type_t& A_cref;
};
with the extra member overhead.
If the macros are usable from the derived classes, they can only need const access - so the macros can use the protected const access function.
Macros that are going to modify the variable will have to use the private variable, and will only be usable in the base class.
It appears that you problems will go away if you replace your TEST() macro with the public function test() in the base class:
class Base
{
public:
void test() { test_files_var.current()->current_test() }
private:
type_t test_files_var;
};
I'm trying to derive a class from a Base that has a friend function defined. I want to create a friend function for my derived class that makes use of the Base's friend function, but preserves the type of my Derived class:
#include<algorithm>
class Base
{
public:
Base(int i, int j, int k)
{
vect[0] = i;
vect[1] = j;
vect[2] = k;
}
~Base();
friend Base myMin (const Base& argA,
const Base& argB);
protected:
// Member data
int vect[3];
};
class Derived : public Base
{
public:
Derived(int i, int j, int k)
:
Base(i,j,k)
{
}
~Derived();
friend Derived doSomething(const Derived& argA,
const Derived& argB);
};
Base
myMin (const Base& argA,
const Base& argB)
{
int i = std::min(argA.vect[0], argB.vect[0]);
int j = std::min(argA.vect[1], argB.vect[1]);
int k = std::min(argA.vect[2], argB.vect[2]);
return Base(i,j,k);
}
Derived doSomething(const Derived& argA,
const Derived& argB)
{
// Does other stuff too...
return myMin(argA, argB);
}
int main(int argc, char *argv[])
{
Derived testA(2,4,6);
Derived testB(3,3,7);
doSomething(testA,testB);
return 0;
}
I understand why this doesn't work (doSomething is given a Base to return, but is told to return Derived), and that this probably isn't very good C++ form. My Base class has a ton of friend functions similar to this, is there a way to make use of the friend functions with my Derived class without having to modify them?
Thank you
Edited: The error, for reference, is:
base.H: In function ‘Derived doSomething(const Derived&, const Derived&)’:
base.H:50:26: error: could not convert ‘myMin(const Base&, const Base&)((* &(& argB)->Derived::<anonymous>))’ from ‘Base’ to ‘Derived’
return myMin(argA, argB);
The most obvious way would be to change doSomething() to
Derived doSomething(const Derived& argA,
const Derived& argB)
{
Base temp(myMin(argA, argB));
Derived retval(temp.vect[0], temp.vect[1], temp.vect[2]);
return retval;
}
You'll probably also have to declare doSomething() to be a friend of Base as well.
Without knowing more about what you are REALLY trying to do, hard to advise further. The fact you need to do this at all is an example of a "code smell" - a positive sign that your design is flawed and, as your code keeps growing, you will keep needing to do workarounds like this. That gradually makes it harder and harder to change the code - each time you change one part, something else has to be worked around.
I understand that the following code doesn't work -- can't convert base to foo.
Is there something I can do, or some pattern to employ which would get me close the behavior I'm trying to achieve in the code below? IOW, if I have a base class pointer to a derived type, how can I invoke a specific method that matches the derived type (not the base type)?
What patterns might I use? I looked into Curiously Recursive (or recurring) Template Pattern, however this imposed other limitations itself.
class base {};
class foo : public base {};
void method(const foo& f){}
int main(){
base* b = new foo();
method(*b);
}
The easiest way is probably to just make method() a virtual member function on foo:
class base {
public:
virtual void method() const = 0;
};
class foo : public base {
public:
void method() const override { }
};
int main(){
foo f;
base* b = &f;
b->method();
}
But if for some reason that is not possible (perhaps you don't have access to method() or perhaps you want to keep the logic in method() separate from foo) you could use a simplified version of the Visitor Pattern.
The visitor pattern relies on all the classes in your hierarchy having a virtual function to dispatch based on class type.
In your case you don't need double-dispatch so you don't actually need the visitor object and can just call your method function directly from a virtual dispatch function:
class base {
public:
virtual void dispatch() const = 0;
};
class foo : public base {
public:
void dispatch() const override;
};
void method(const foo& f){}
void foo::dispatch() const {
method(*this);
}
int main(){
foo f;
base* b = &f;
b->dispatch();
}
You have to remember that in most contexts the compiler doesn't know that your base pointer is actually of type foo.
Use virtual functions to solve these kinds of problems:
class base {
public:
virtual void func() const { /* A */ }
};
class foo : public base {
public:
void func() const override { /* B */ }
};
void method(const base& f) {
f.func();
}
int main(){
base* b = new foo();
method(*b);
}
Now, depending on the actual type of f, either A or B code will be executed in method.
In the below program, the function 'f' in the base class A is hidden for the objects of derived class B. But when I call function f through const A *d which is pointing object of B, function f from the base class is getting invoked. If I remove const specifier for the pointer (i.e. A *d) function 'f' from derived class is called. My query how the constness is making a difference here ? Thanks for any help.
#include <iostream>
class A
{
public:
virtual void f(int n) { std::cout << "A::f\n"; }
virtual ~A() { }
void f(int n) const { std::cout << "A::f const\n"; }
};
class B
: public A
{
public:
void f(int n) { std::cout << "B::f\n"; }
void f(int n) const { std::cout << "B::f const\n"; }
};
int main()
{
const A a;
B b;
A &c = b;
const A *d = &b;
c.f(1);
d->f(1);
return 0;
}
Output (with const A *d):
B::f
A::f const
Output (with A* d)
B::f
B::f
The signature of the function to be called is determined on call site based on the static type of the pointer. The correct overrider of this signature is then chosen at runtime.
In other words, if you have this:
const A *d;
d->f(1);
then the f is searched for in const A. So it finds the non-virtual void f(int) const.
However, if you have this:
A *e;
e->f(1);
then the f is searched for in non-const A. So it finds virtual void f(int), which is then (at runtime) delegated to the final overrider void B::f(int).
EDIT
This follows from the rules on member function selection. When accessing through a const path (pointer or reference), only const member functions are applicable. When accessing through a non-const path, non-const functions are considered. Only if there is none is the pointer (or reference) implicitly converted to a pointer (or-reference) to const and then the const member functions are considered.
I have searched far and wide for a specific answer to this question, and cannot find it. I am trying to create a base class with a virtual operator> that I can override in the derived class. Currently I'm having problems because declaring the function only requires one input variable (as in "bool operator> (Derived & a)" but attempting to define it in a cpp file tells me that it requires two inputs (as in "bool operator> (Derived & a, Derived & b))
I've tried defining the operator inline, but then I get errors where it thinks the derived class is still abstract because I'm passing in the derived type to the operator as shown above, instead of the base class. But if I pass the base class, then I cannot access the derived member variables I need to make the comparison.
I think I'm missing something simple here but I cannot seem to figure out what it is.
Hopefully you can help.
Thanks
For virtual calls to work from a reference/pointer of the base, you will need to use the base-type in the function, so for example
class Derived : public Base
{
....
bool operator>(Base &a)
{
Derived *pa = dynamic_cast<Derived *>(&a);
return this->something > pa->something; // Or whatever...
}
....
};
If you change the type, it becomes a different function, and when you use the base pointer or reference to refer to operator>, it will use the one in the base-class.
Why don't you leave operator>() non-virtual, und have it call a private virtual function?
Like so:
class Base {
public:
bool operator>(Base &a) {
return implementingFunction(a);
}
private:
virtual bool implementingFunction(Base &a) = 0;
};
#include <iostream>
using namespace std;
class base{
public :
virtual bool operator> (base& obj) { cout<<"b\n";return true;}
virtual ~base(){}
};
class derived: public base{
public:
virtual bool operator> (derived& obj) { cout<<"d\n";return true;}
~derived(){}
};
int main()
{
base *a=new derived(),b;
if(*a>b) { delete a; cout<<"Done!\n"; }
return 0;
}
Old question, but I've hardly seen a useful/correct answer here, so I would add my suggestion:
struct base
{
virtual ~base() = default;
virtual bool operator> (base const& obj) const = 0;
};
struct derived: public base
{
derived(int member) : member(member) {}
int member = 0;
virtual bool operator> (base const& obj) const
{
return member > static_cast<derived const&>(obj).member;
}
};
int main()
{
//in reality one would use a unique_ptr, of course
base* a = new derived(1);
base* b = new derived(0);
if(*a > *b)
{
//do something
}
return 0;
}
Caution: this works safely only if you're sure that the base const& parameter is really a derived const& (as e.g. in CRTP).
If not, you should use a dynamic_cast and add some error handling.