#include <iostream>
using namespace std;
class A {
};
typedef void (A::*funA)(int);
class B : public A {
public:
void m(int) {std::cout << "mm" << std::endl; }
void n(int) { std::cout << "nn"<<std::endl; }
};
typedef void (B::*funB)(int);
class C : public B {
public:
void g(int) {std::cout << "gg" << std::endl; }
void h(int) { std::cout << "hh"<<std::endl; }
};
typedef void (C::*funC)(int);
int main() {
funB f = static_cast<funB>(&C::m);
A* pa = new A;
(pa->*(static_cast<funA>(f)))(2);
return 0;
}
gcc compile and output "mm".
But why can this work? Class A in fact don't define any function.
It seems the class can use its base class or derived class function by this way, even though it doesn't define them.
Since A doesn't contain the member that f refers to, the behaviour is undefined.
The probable reason why it works anyway is that the function B::m doesn't touch the this pointer, so it doesn't "notice" when it's called on an object of the wrong type. Also, A and B are not polymorphic, so dereferencing the pointer-to-member and calling doesn't require examining any vptr.
Related
I'm trying to replace a function in super class A in order to extend its functionality in B class, but without losing the old definition. So is there any way to force the A::b method to use a new definition from B class? I have experience in Java, so I know it is possible in this language. Expected output is
A::b
B::a
A::a
Current output is
A::b
A::a
#include <iostream>
using namespace std;
class A {
protected:
static void a() {
cout << "A::a" << endl;
}
public:
void b() {
cout << "A::b" << endl;
a();
}
};
class B: public A {
protected:
static void a() {
cout << "B::a" << endl;
A::a();
}
};
int main()
{
B b;
b.b();
return 0;
}
https://godbolt.org/z/dnY5o8WfK
I think you meant to use virtual keyword instead of static as shown below, since static in this context means that there is no implicit this parameter for the non-static member function a.
#include <iostream>
using namespace std;
class A {
protected:
virtual void a() { //note the virtual keyword
cout << "A::a" << endl;
}
public:
void b() {
cout << "A::b" << endl;
a();
}
};
class B: public A {
protected:
virtual void a() {//note the virtual keyword
cout << "B::a" << endl;
A::a();
}
};
int main()
{
B b;
b.b();
return 0;
}
The output of the above program can be seen here:
A::b
B::a
A::a
By using virtual we're making the member function a to be a virtual member funciton.
Is there a way that we can call derived class's method from base class object for which base doesn't provide an interface to call? I would like to do something like this
template<typename T>
struct A
{
using Derived = T;
void print()
{
static_cast<T*>(this)->print_();
}
void print_()
{
std::cout << "Base" << std::endl;
}
void a()
{
std::cout << "Aa" << std::endl;
}
};
struct B : public A<B>
{
void print_()
{
std::cout << "BD" << std::endl;
}
void b()
{
std::cout << "Bb" << std::endl;
}
};
struct C : public A<C>{
void c()
{
std::cout << "Cc" << std::endl;
}
};
int main()
{
A<B> b;
A<C> c;
b.print();
c.print();
B bd;
b.a();
bd.b(); // This works
// b.b(); // I understand this doesn't work, but I want to make this work.
C bc;
c.a();
bc.c(); // Same as class A<C> and C
}
I can provide interfaces to call those functions but I would like to know if this is achievable in the first place. Any solutions or comments on feasibility is much appreciated.
PS: I am just curious about this, as I got an unintentional error when I incorrectly instantiated the class.
Is there a way that we can call derived class's method from base class object for which base doesn't provide an interface to call?
Yes, as Jarod42 suggested, you can implement operator-> in A. You can't overload operator. so you'll have to use -> when calling such methods.
template<typename T>
struct A {
T* operator->() { return static_cast<T*>(this); }
};
You will now be able to compile this:
A<B> b;
b->print_();
b->b();
But: Your program will have undefined behavior. b is not a B. It's an A<B> that doesn't inherit from B so you will call non-static member functions on a non-existing object.
I suggest that you prevent instantiating A:s that doesn't have the proper CRTP relationship.
template<typename T>
struct A {
T* operator->() { return static_cast<T*>(this); }
private:
A() = default; // hidden from all ...
friend T; // ... except T
};
You can now instantiate B, but not A<B> or C if someone makes a bogus inheritance like this:
struct X {};
struct C : A<X> {}; // C can't be instantiated. A is friend of X, not C
Demo
Simple case: If you add a static function there is a safe way (because it would not access instance date).
Complicated case: the b.b(): This almost works but it's definitely a bad idea. As long as function does not refer to any instance variable it would be relatively safe. But otherwise it will definitely crash. The reason is b does not have B instance.
template<typename T>
struct A
{
typedef typename T Derived;
typedef typename A<T> AT;
void print()
{
static_cast<T*>(this)->print_();
}
void print_()
{
std::cout << "Base" << std::endl;
}
void a()
{
std::cout << "Aa" << std::endl;
}
//these conversion operators are for b.b() case. very bad idea!
operator Derived* () {
return static_cast<T*>(this);
}
operator Derived& () {
return static_cast<Derived&>(*this);
}
};
struct B : public A<B>
{
void print_()
{
std::cout << "BD" << std::endl;
}
static void static_b()
{
std::cout << "Bb::static_b" << std::endl;
}
void b()
{
std::cout << "Bb::b" << std::endl;
}
};
void test()
{
b.A<B>::Derived::static_b(); // This should work.
b.AT::Derived::static_b(); // This works with "AT" but it's recursive template. Not good.
((B&)b).b(); //This works but even though operator is implicit, it cannot implicitly know what to do. Nor will "auto".
//This works but even though operator is implicit, it cannot implicitly know what to do. Nor will "auto".
B& br = b;
br.b();
}
Why is the output of this program "CLASS A"? Isn't this determined to be of type B? Doesn't it mean that this->g() should call the B class's version of g?
#include <iostream>
using namespace std;
class A {
private:
void g() {
cout << "CLASS A" << endl;
}
public:
virtual void f() {
g();
}
};
class B : public A {
public:
void g() {
cout << "CLASS B" << endl;
}
};
int main() {
A* a = new B();
a->f();
}
Isn't this determined to be of type B?
No. B may be the dynamic type, but the static type of *this is A within all its member functions.
The member function g is not virtual, so therefore a call to it uses static binding. In static binding, the dynamic type of the object is irrelevant - only the static type matters. A call to the non-virutal g within a member function of A should be a call to A::g.
Reading through a text book, I have come away with the impression that overriding virtual functions only works when using a pointer or reference to the object. The book demonstrates the creation of a pointer of the base class type pointed to an object the derived class type, and uses that to demonstrate a virtual function override.
However, I've now come across the following. Not a pointer in sight, and I was expecting that making function1 virtual would not make a difference, but it does. I'm clearly missing something here and would appreciate an explanation as to what it is. Sorry if my explanation isn't clear; also I expect this has been asked before, but was unable to come up with what to search on.
using namespace std;
class ClassA
{
public:
void function1(); // virtual or not?
void function2();
};
class ClassB : public ClassA
{
public:
void function1();
};
int main()
{
ClassA objA;
ClassB objB;
objA.function1();
cout << "\n";
objA.function2();
cout << "\n";
objB.function1();
cout << "\n";
objB.function2(); // Fourth call
cout << "\n";
}
void ClassA::function1() { cout << "ClassA::function1\n"; }
void ClassA::function2()
{
cout << "ClassA::function2\n";
function1(); // For the fourth call ClassA::function1()
// is called if ClassA::function1() is not virtual
// but ClassB:function1() is called if it is. Why?
}
void ClassB::function1() { cout << "ClassB::function1\n"; }
Many thanks for any help.
It's not a virtual function as it is not marked as one. It's simply a public function accessible from a derived class / object. Your code is not exhibiting polymorphic behavior either. That being said none of your functions are virtual nor overriding. Trivial example for polymorphic installation would be:
#include <iostream>
#include <memory>
class ClassA {
public:
virtual void function1() { // now virtual
std::cout << "ClassA::function1\n";
}
};
class ClassB : public ClassA {
public:
void function1() override {
std::cout << "ClassB::function1\n";
}
};
int main() {
std::unique_ptr<ClassA> p = std::make_unique<ClassB>();
p->function1(); // now calls class B function, overrides class A behavior
}
or through references:
int main() {
ClassB objB;
ClassA& ro = objB;
ro.function1(); // now calls class B function, overrides class A behavior
}
There is little benefit in marking functions as virtual and override if you are not utilizing polymorphic behaviour.
Example of virtual without explicit pointers :
class A
{
public:
virtual void f1()
{
cout << "A::f1()" << endl;
}
void f2()
{
f1();
}
};
class B : public A
{
public:
void f1() override
{
cout << "B::f1()" << endl;
}
};
int main()
{
A a;
B b;
a.f2();
b.f2();
}
function1 is not virtual, obj2 calls the classB function1 because it is a clasB object, the compiler first looks at the most-derived type for a function, then the leftmost base (and on through the bases of that base), and then the next base in multiple inheritance situations. If you took a classA * to obj2 and called function1 it would call the classA function1.
I have these two classes:
class A {
public:
A() { m_ptr = NULL; }
void (*m_ptr)();
void a() { if (m_ptr) m_ptr(); }
};
class B : public A {
public:
B() { m_ptr = b; }
void b() {
std::cout << "B::b() is called" << std::endl;
}
};
And I want to use them like this:
B b;
b.a();
and get the following to be called B::b().
Of course this is not being compiled as B::b is not of type void(*)().
How can I make it work?
UPDATE. To whom who asks "why?" and "what for?".
The class A is a very basic class which has many successors in production code. The class B is 6-th successor and I want to extend A (the most convinient place) to call there one more method (from B) which can be present and may be not in another successors af A and B.
A virtual method with empty body can be employed for that but it is ugly and I want to avoid it. Abstract method even more so (because of existing derived successors code).
I don't want to use external function of type void (*)() to not loose access to internal data of all hierarchy.
You can't make it work as your classes are defined now.
Calling a non-static member function of another class requires an instance of that class. You either need to store a reference to the object that owns the member function when storing the function pointer, or pass a reference to the object when you make the call to A::a.
You also need to declare m_ptr with the type void (B::*)(), which is pointer to member of B that is a function taking no parameters and returning void.
Look at this example:
class A {
public:
A() { m_ptr = nullptr; }
void a(B& b) { if (m_ptr) (b.*m_ptr)(); } // Now takes reference to B object.
void (B::*m_ptr)(); // Pointer to member function of B.
};
class B : public A {
public:
B() { m_ptr = &B::b; } // Adress of qualified function.
void b() {
std::cout << "B::b() is called" << std::endl;
}
};
Now we can call B::b like this:
B b;
b.a(b); // Pass reference to b when calling.
Your use of inheritence in this way is confusing as it implies that the real problem you are trying to solve is to invoka a member of a derived class through the base class. This is usually accomplished using a simple virtual function like this:
class A {
public:
virtual ~A() {}
void a() const { b(); } // Call b.
private:
virtual void b() const {}
};
class B : public A {
public:
virtual void b() const override { // C++11 override specifier (optional).
std::cout << "B::b() is called" << std::endl;
}
};
And used like this:
B b;
b.a(); // B::b is called.
Well, probably not the purpose of this exercise, but you can simply declare static void b() if you want to make it work.
Another option is to declare friend void b(), but then the "B::b() is called" printout would be stating a wrong fact.
I would suggest using CRTP since you want to avoid virtual mechanism. Note, however, your code might require some design changes to accommodate this pattern. But it does provide type safety and has no run-time overhead. Hope it helps.
Code on ideone.com:
#include <iostream>
#include <type_traits>
namespace so {
class B;
template<typename T>
class A {
public:
template<typename U = T, typename = typename std::enable_if<std::is_same<U, B>::value>::type>
void foo_A() {
std::cout << "foo_A : ";
static_cast<U *>(this)->foo_B();
}
};
class B: public A<B> {
public:
void foo_B() {
std::cout << "foo_B" << std::endl;
}
};
class C: public A<C> {
public:
void foo_C() {
std::cout << "foo_C" << std::endl;
}
};
} // namespace so
int main() {
so::B b_;
so::C c_;
b_.foo_A();
b_.foo_B();
//c_.foo_A(); Compile error: A<C>::foo_A() does not exist!
c_.foo_C();
return (0);
}
Program output:
foo_A : foo_B
foo_B
foo_C