Fooling a bit around in C++, I stumbled across something which I believe is an error of both clang++ (6.0) and g++ (5.3): I am able to trick the compiler to call functions it should not be able to.
In short, I am declaring an abstract base class from which I derive two classes: a non-abstract and an abstract, which are related only via their common base class but have different functions. Instantiating the non-abstract base class and tricking the compiler to create a pointer of the abstract derived class pointing to the non-derived, I am able to call - via that pointer - a function of the original non-abstract class and the abstract class.
Minimal example, the two lines which give me a headache are at the bottom, separated by a comment line with stars:
#include <cassert>
#include <iostream>
#include <typeinfo>
class MYBase {
public:
virtual void fun1() = 0;
};
class MYDer1 : public MYBase {
public:
~MYDer1() { std::cout << "~MYDer1()\n"; }
void fun1() { std::cout << "MYDer1 fun1\n"; }
};
class MYDer2 : public MYBase {
public:
~MYDer2() { std::cout << "~MYDer2()\n"; }
void something2() { std::cout << "MYDer2 something2\n"; }
};
int main () {
MYDer1 x1;
// Good: cannot instantiate a 'MYDer2' as it is an abstract class
// due to unimplemented pure virtual method 'fun1' in 'MYDer2'
//
// MYDer2 x2;
// Good, clang++ and g++ rightfully refuse to compile this:
//
// auto * pd2 = static_cast<MYDer2 *>(&x1);
// So let's be 'clever' and take a detour via 'void':
auto * pd2 = static_cast<MYDer2 *>(static_cast<void *>(&x1));
// Just to be sure the compiler got it right
assert(typeid(pd2) == typeid(MYDer2 *));
/***********************************************************/
// There is no "fun1" declared in MYDer2
// So why does this even compile?
pd2->fun1();
// And why does this execute correctly?
pd2->something2();
return 0;
}
What am I missing?
It is undefined behavior so this time you shot yourself in the leg but missed. It is a programmer's responsibility to ensure that pointer being dereferenced really points to the object of specified type.
This is undefined behavior because x1 is of type MYDer1 and you cast it by force to MYDer2. The code might not work because you are not really doing anything with function something2. Try to add a member variable to MYDer2 and print it to see the problem.
Related
I was doing an experiment on inheritance and abstract classes without using pointers (avoiding the use of new when possible), and I came across a behavior that makes sense but I havent found documentation on it on the internet (neither a name for it or example).
I create a class, Abstract that has two methods, one is defined and the other is not. Then, a class Inherited inherits from Abstract and implements this second method.
Heres the classes:
Abstract.hpp:
#ifndef ABSTRACT_HPP
# define ABSTRACT_HPP
#include <iostream>
class Abstract {
public:
Abstract() {};
~Abstract() {};
virtual void DoSomethingAbstract() = 0;
void DoSomethingNormal() {
std::cout << "Inside Abstract::DoSomethingNormal" << std::endl;
DoSomethingAbstract();
}
};
#endif /* ABSTRACT_HPP */
Inherited.hpp :
#ifndef Inherited_HPP
# define Inherited_HPP
#include "Abstract.hpp"
class Inherited : public Abstract {
public:
Inherited() {};
~Inherited() {};
virtual void DoSomethingAbstract() {
std::cout << "Inside Inherited::DoSomethingAbstract" << std::endl;
}
};
#endif /* Inherited_HPP */
The following main works as expected (the only implementation of each function is the one that is called):
#include "Abstract.hpp"
#include "Inherited.hpp"
int main() {
Inherited a;
a.DoSomethingNormal();
return 0;
}
output:
Inside Abstract::DoSomethingNormal
Inside Inherited::DoSomethingAbstract
Mostly I'd like to know if this is a UB and I'm just getting lucky, an unfrequent way of checking runtime polymorphism (which should not since there are no pointers to abstract classes here), or a perfectly defined behaviour somewhere in the standard.
PS: I am compiling with g++ 9.4.0, with flags `-std=c++98 -Wno-c++0x-compat.
Your example seems simple -- and for the most part, it is. But it leads to some important concepts. First, what you can do is a google on c++ polymorphism. There are a lot of hits, and the first several didn't seem to be wrong.
Let's look at some of your code:
virtual void DoSomethingAbstract() = 0;
This is referred to as a pure virtual function. It means you won't actually make this method, but you're going to reserve a slot for it (and can call it). It means you can not make instances of this class -- it's abstract. If you try to make one, the compiler will complain. Your subclasses MUST provide implementations or they are also abstract and can't be instantiated.
void DoSomethingNormal() {
std::cout << "Inside Abstract::DoSomethingNormal" << std::endl;
DoSomethingAbstract();
}
This method is NOT virtual. Your subclass can make its own copy of this method, but then you can get weird results. Let's say you do this:
class Inherited: public Abstract {
public:
void DoSomethingNormal() {...}
};
void blah(Abstract &obj) {
obj.DoSomethingNormal();
}
It won't matter whether you pass in an Abstract or an Inherited -- because you didn't declare the method virtual, and because blah() doesn't know what you're passing in but thinks it's an Abstract, you'll get Abstract's version of DoSomethingNormal().
But if you declare the method virtual, you're saying, "Use whichever version corresponds to the class that actually was instantiated."
This is polymorphism at it's most useful, important role.
I have an issue where the method I'm trying to call isn't called and some other method is called instead. It is in a very weird and big design but I managed to do a example out of it. The example is still big the it's the smaller I've been able to do.
#include <iostream>
#include <vector>
class IObserver
{
};
class IAObserver : public IObserver
{
public:
virtual void someSpecificMethod(int i) = 0;
};
class ISomeOtherObject
{
public:
virtual void someMethodFromThatObject() = 0;
};
class SomeOtherObject : public ISomeOtherObject
{
public:
virtual void someMethodFromThatObject()
{
std::cout << "Some implementation from that object" << std::endl;
}
};
class AObserverImpl : public IAObserver, public SomeOtherObject
{
public:
virtual void someSpecificMethod(int i)
{
std::cout << "Some implementation " << i << std::endl;
}
virtual void someMethodFromThatObject()
{
std::cout << "Better implementation from our object" << std::endl;
}
};
class Base
{
public:
virtual void addObserver(IObserver* observer) = 0;
};
class A : public Base
{
public:
virtual void addObserver(IObserver* observer)
{
m_observers.push_back((IAObserver*)observer);
}
void notifyObservers()
{
std::vector<IAObserver*>::iterator it;
for(it = m_observers.begin(); it != m_observers.end(); it++)
{
(*it)->someSpecificMethod(5);
}
}
private:
std::vector<IAObserver*> m_observers;
};
int main()
{
A* a = new A();
SomeOtherObject* observer = new AObserverImpl();
a->addObserver((IObserver*)observer);
a->notifyObservers(); //output: Better implementation from our object
}
Here's the Ideone http://ideone.com/yAT6M7
So as you can see, it is supposed to call the method someSpecificMethod but it's calling the mehod someMethodFromThatObject. Any clue what's going on ? Is this object slicing ? In CLion debugger, I can't even call my someSpecificMethod method. How can I work around this ?
The problem is that you are using C-style casts, when you should be using a dynamic_cast instead.
C-style casts know nothing of C++ objects, and therefore they do no type checking. In order to cast between base classes in a multiple-inheritance situation, you must use a dynamic_cast to make sure that everything is set up correctly for the new pointer.
If you replace all of the C-style casts in your sample to dynamic_cast, then it should work.
If you want to read more about this, search for C++, v-tables, and multiple inheritance.
At the core of your problem is a cross-cast. You have an inheritance hierarchy that looks like this:
[SomeOtherObject] [IAObserver]
\ /
\ /
[AObserverImpl]
Inside main(), observer has dynamic type AObserverImpl*, but static type SomeOtherObject*. Then you try to retrieve the IAObserver part of the object which also contains this SomeOtherObject. This is called a cross-cast, a cast across the inheritance tree of an object.
But by the time you do the cast, the information that *observer is actually part of an AObserverImpl has been lost from the type system. So the C-style cast, which is strictly static, degrades into a reinterpret_cast (!!). You get an IAObserver* that actually still points to the very same SomeOtherObject, and trying to then use it only leads to nasty bugs at best.
This is the kind of reasons why you should never use a C-style cast on pointers unless you have a good reason and you know it. Had you used a static_cast, it would have failed to compile.
To solve this, you need to somehow get back the lost type information to perform your cast. Two parties still have that information:
The developer:
// Downcast to AObserverImpl, then upcast along the other branch
// The upcast is superfluous, but written here for clarity
a->addObserver(
static_cast<IAObserver*>(
static_cast<AObserverImpl*>(observer)
)
);
And... dynamic_cast:
// dynamic_cast uses RTTI to walk the inheritance graph at runtime.
// It will also do error checking :)
a->addObserver(dynamic_cast<IAObserver*>(observer));
In c++11 the override specifier protects from not overriding an intended virtual base function (because the signatures do not match).
The final specifier protects from unintentionally overriding a function in a derived class.
=> Is there a specifier (something like maybe first or no_override) that protects from overriding an unknown base function?
I'd like to get a compiler error when a virtual function was added to a base class with the same signature as an already existing virtual function in a derived class.
EDIT 4: To keep this question simple and answers relevant, here is again the
original pseudo-code
abstract class B : A has private: virtual void fooHasBeenDone() = 0;
class C : B implements private: virtual void fooHasBeenDone() override { react(); }
Now class A gets a new private: virtual void fooHasBeenDone();
But the new A::foo could be something different than the original B::foo.
and a specific example
abstract class B : A has virtual void showPath() = 0; meaing a PainterPath
class C : B implements virtual void showPath() override { mPath.setVisible(); }
Now class A gets a new virtual void showPath(); meaning a file path
Now when A calls showPath(), B shows the painterPath instead of some file path.
Of course this is wrong, and I should then rename B::showPath() to B::showPainterPath() and implement B::showPath() override as well. I'd just like to get informed by the compiler.
Here is a compiling real-world example:
#include <iostream>
#define A_WITH_SHOWPATH
class A
{
#ifdef A_WITH_SHOWPATH
public:
void setPath(std::string const &filepath) {
std::cout << "File path set to '" << filepath << "'. Display it:\n";
showPath();
}
// to be called from outside, supposed to display file path
virtual void showPath() {
std::cout << "Displaying not implemented.\n";
}
#else
// has no showPath() function
#endif
};
class B : public A
{
public:
virtual void showPath() = 0; // to be called from outside
};
class C1 : public B {
public:
virtual void showPath() override {
std::cout << "C1 showing painter path as graphic\n";
}
};
class C2 : public B {
public:
virtual void showPath() override {
std::cout << "C2 showing painter path as widget\n";
}
};
int main() {
B* b1 = new C1();
B* b2 = new C2();
std::cout << "Should say 'C1 showing painter path as graphic':\n";
b1->showPath();
std::cout << "---------------------------\n";
std::cout << "Should say 'C2 showing painter path as widget':\n";
b2->showPath();
std::cout << "---------------------------\n";
#ifdef A_WITH_SHOWPATH
std::cout << "Should give compiler warning\n or say \"File path set to 'Test'. Display it:\"\n and \"Displaying not implemented.\",\n but not \"C1 showing painter path as graphic\":\n";
b1->setPath("Test");
std::cout << "# Calling setPath(\"Test\") on a B pointer now also displays the\n# PainterPath, which is not the intended behavior.\n";
std::cout << "# The setPath() function in B should be marked to never override\n# any function from the base class.\n";
std::cout << "---------------------------\n";
#endif
return 0;
}
Run it and look at the text output.
For reference, an older example with a specific use-case (PainterPath instance):
https://ideone.com/6q0cPD (link may be expired)
The facility of specifiers like first or no_override is not there as such. Probably because it may create confusion. However, it can trivially be achieved by changing the approach.
One should add any new method in the base class with final specifier. This will help to get the compiler error for any matching signatures. Because, it will make the subsequent derived class method signatures automatically as "first" of their kind. Later the final keyword can be removed, as it was intended just for "first hand verification".
Putting & removing final keyword after the newly added base method is analogically similar to compiling binary with debug (g++ -g) option, which helps you to fix bug. In production that debug option is removed for optimization.
From your example:
class A {}; // no method, no worry
class B {
public: virtual void showPath() = 0; // ok
};
...
Now accidentally you are adding similar method in A, that results in error:
class A {
public: virtual void showPath() final; // same signature by chance
// remove the `final` specifier once the signature is negotiated
};
class B {
public: virtual void showPath() = 0; // ERROR
};
So the signatures between new A::showPath() & existing B::showPath() have to be negotiated & then carry on by removing final specifier.
This answer is community wiki because it combines all other answers. Please upvote the specific answer that was helpful to you as well as this one.
No, there is no specifier like first or no_override. (answer)
You should use the override specifier as often as possible.
Qt has a macro Q_DECL_OVERRIDE that expands to override, if available.
If not available, at least mark each overriding function with a comment.
If you do that, there are compiler flags that warn about a missing override:
"Clang now has -Winconsistent-missing-override, and newer GCCs have -Wsuggest-override."
I don't know of a VS2012 flag for this. Feel free to edit.
You can mimic the desired behavior by adding a 'secret' that the base class cannot know. (answer)
This is helpful in very specific use cases, but generally breaks the concept of virtuality (see comments to the other answers).
If you don't own the base class and have a conflict (e.g. compiler warning), you will need to rename your virtual function in all derived classes.
If you own the base class, you can temporarily add a final to any new virtual function. (answer)
After the code compiles without errors, you know that no function of that name and signature exists in any derived class, and you can remove the final again.
... I think I'll start marking first virtual functions as DECL_FIRST. Maybe in the future there will be a compiler-independent way of checking this.
No there is not.
Adding a virtual function to a base class that has the same signature as a virtual function in a child class cannot break any existing functionality unless adding that virtual function turns the base class into a polymorphic type. So in the norm, it's benign, and a purest would argue, adding language features to guard against this would be rather pointless.
(Of course you could mark your new function final just to check that a child class function isn't going to clobber it.)
Your only option is to resort to code analysis tools.
(Note that VS2012 does not implement, or even claim to implement, the C++11 standard, although it does have some of it.)
C++ doesn't seem to provide such means out of the box. But you can mimic it like follows:
template<class Base>
class Derived : public Base
{
private:
struct DontOverride {};
public:
// This function will never override a function from Base
void foo(DontOverride dummy = DontOverride())
{
}
};
If you intend to introduce a new virtual function, then do it like below:
template<class Base>
class Derived : public Base
{
protected:
struct NewVirtualFunction {};
public:
// This function will never override a function from Base
// but can be overriden by subclasses of Derived
virtual void foo(NewVirtualFunction dummy = NewVirtualFunction())
{
}
};
conv.h
class Base
{
public:
void foo();
};
class Derived: public Base
{
public:
void bar();
};
class A {};
class B
{
public:
void koko();
};
conv.cpp
void Base::foo()
{
cout<<"stamm";
}
void Derived::bar()
{
cout<<"bar shoudn't work"<<endl;
}
void B::koko()
{
cout<<"koko shoudn't work"<<endl;
}
main.cpp
#include "conv.h"
#include <iostream>
int main()
{
Base * a = new Base;
Derived * b = static_cast<Derived*>(a);
b->bar();
Derived * c = reinterpret_cast<Derived*>(a);
c->bar();
A* s1 = new A;
B* s2 = reinterpret_cast<B*>(s1);
s2->koko();
}
output:
bar shoudn't work
bar shoudn't work
koko shoudn't work
How come the method bar is succeeded to be called in run time despite that I have created a Base class not derived?? it works even with two types of conversions (static and reinterpret cast).
same question as above but with unrelated classes (A & B) ??
Undefined behaviour can do anything, including appear to work.
It's working (read: "compiling and not crashing") 'cause you never use the this pointer in your nominally "member" functions. If you tried to print out a member variable, for example, you'd get the garbage output or crashes you expect - but these functions as they are now don't depend on anything in the classes they're supposedly part of. this could even be NULL for all they care.
The compiler knows a Derived can use member functions foo() and bar() and knows where to find them. After you did your "tricks", you had pointers to Derived.
The fact that they were pointers of type Derived -- regardless of what data was associated with those pointers -- allowed them to call the functions foo() and kook() associated with Derived.
As has been mentioned, if you had actually used the data at the pointers (i.e. read or wrote data members relative to this belonging to the Derived class (which you don't have in this case), you would have been access memory that didn't belong to your objects.
I'm having trouble understanding what the purpose of the virtual keyword in C++. I know C and Java very well but I'm new to C++
From wikipedia
In object-oriented programming, a
virtual function or virtual method is
a function or method whose behavior
can be overridden within an inheriting
class by a function with the same
signature.
However I can override a method as seen below without using the virtual keyword
#include <iostream>
using namespace std;
class A {
public:
int a();
};
int A::a() {
return 1;
}
class B : A {
public:
int a();
};
int B::a() {
return 2;
}
int main() {
B b;
cout << b.a() << endl;
return 0;
}
//output: 2
As you can see below, the function A::a is successfully overridden with B::a without requiring virtual
Compounding my confusion is this statement about virtual destructors, also from wikipedia
as illustrated in the following example,
it is important for a C++ base class
to have a virtual destructor to ensure
that the destructor from the most
derived class will always be called.
So virtual also tells the compiler to call up the parent's destructors? This seems to be very different from my original understanding of virtual as "make the function overridable"
Make the following changes and you will see why:
#include <iostream>
using namespace std;
class A {
public:
int a();
};
int A::a() {
return 1;
}
class B : public A { // Notice public added here
public:
int a();
};
int B::a() {
return 2;
}
int main() {
A* b = new B(); // Notice we are using a base class pointer here
cout << b->a() << endl; // This will print 1 instead of 2
delete b; // Added delete to free b
return 0;
}
Now, to make it work like you intended:
#include <iostream>
using namespace std;
class A {
public:
virtual int a(); // Notice virtual added here
};
int A::a() {
return 1;
}
class B : public A { // Notice public added here
public:
virtual int a(); // Notice virtual added here, but not necessary in C++
};
int B::a() {
return 2;
}
int main() {
A* b = new B(); // Notice we are using a base class pointer here
cout << b->a() << endl; // This will print 2 as intended
delete b; // Added delete to free b
return 0;
}
The note that you've included about virtual destructors is exactly right. In your sample there is nothing that needs to be cleaned-up, but say that both A and B had destructors. If they aren't marked virtual, which one is going to get called with the base class pointer? Hint: It will work exactly the same as the a() method did when it was not marked virtual.
You could think of it as follows.
All functions in Java are virtual. If you have a class with a function, and you override that function in a derived class, it will be called, no matter the declared type of the variable you use to call it.
In C++, on the other hand, it won't necessarily be called.
If you have a base class Base and a derived class Derived, and they both have a non-virtual function in them named 'foo', then
Base * base;
Derived *derived;
base->foo(); // calls Base::foo
derived->foo(); // calls Derived::foo
If foo is virtual, then both call Derived::foo.
virtual means that the actual method is determined runtime based on what class was instantiated not what type you used to declare your variable.
In your case this is a static override it will go for the method defined for class B no matter what was the actual type of the object created
So virtual also tells the compiler to call up the parent's destructors? This seems to be very different from my original understanding of virtual as "make the function overridable"
Your original and your new understanding are both wrong.
Methods (you call them functions) are always overridable. No matter if virtual, pure, nonvirtual or something.
Parent destructors are always called. As are the constructors.
"Virtual" does only make a difference if you call a method trough a pointer of type pointer-to-baseclass. Since in your example you don't use pointers at all, virtual doesn't make a difference at all.
If you use a variable a of type pointer-to-A, that is A* a;, you can not only assign other variables of type pointer-to-A to it, but also variables of type pointer-to-B, because B is derived from A.
A* a;
B* b;
b = new B(); // create a object of type B.
a = b; // this is valid code. a has still the type pointer-to-A,
// but the value it holds is b, a pointer to a B object.
a.a(); // now here is the difference. If a() is non-virtual, A::a()
// will be called, because a is of type pointer-to-A.
// Whether the object it points to is of type A, B or
// something entirely different doesn't matter, what gets called
// is determined during compile time from the type of a.
a.a(); // now if a() is virtual, B::a() will be called, the compiler
// looks during runtime at the value of a, sees that it points
// to a B object and uses B::a(). What gets called is determined
// from the type of the __value__ of a.
As you can see below, the function A::a is successfully overridden with B::a without requiring virtual
It may, or it may not work. In your example it works, but it's because you create and use an B object directly, and not through pointer to A. See C++ FAQ Lite, 20.3.
So virtual also tells the compiler to call up the parent's destructors?
A virtual destructor is needed if you delete a pointer of base class pointing to an object of derived class, and expect both base and derived destructors to run. See C++ FAQ Lite, 20.7.
You need the virtual if you use a base class pointer as consultutah (and others while I'm typing ;) ) says it.
The lack of virtuals allows to save a check to know wich method it need to call (the one of the base class or of some derived). However, at this point don't worry about performances, just on correct behaviour.
The virtual destructor is particulary important because derived classes might declare other variables on the heap (i.e. using the keyword 'new') and you need to be able to delete it.
However, you might notice, that in C++, you tend to use less deriving than in java for example (you often use templates for a similar use), and maybe you don't even need to bother about that. Also, if you never declare your objects on the heap ("A a;" instead of "A * a = new A();") then you don't need to worry about it either. Of course, this will heavily depend on what/how you develop and if you plan that someone else will derive your class or not.
Try ((A*)&b).a() and see what gets called then.
The virtual keyword lets you treat an object in an abstract way (I.E. through a base class pointer) and yet still call descendant code...
Put another way, the virtual keyword "lets old code call new code". You may have written code to operate on A's, but through virtual functions, that code can call B's newer a().
Say you instantiated B but held it as an instance of an A:
A *a = new B();
and called function a() whose implementation of a() will be called?
If a() isn't virtual A's will be called. If a() was virtual the instantiated sub class version of a() would be called regardless of how you're holding it.
If B's constructor allocated tons of memory for arrays or opened files, calling
delete a;
would ensure B's destructor was called regardless as to how it was being held, be it by a base class or interface or whatever.
Good question by the way.
I always think about it like chess pieces (my first experiment with OO).
A chessboard holds pointers to all the pieces. Empty squares are NULL pointers. But all it knows is that each pointer points a a chess piece. The board does not need to know more information. But when a piece is moved the board does not know it is a valid move as each pice has different characteristica about how it moves. So the board needs to check with the piece if the move is valid.
Piece* board[8][8];
CheckMove(Point const& from,Point const& too)
{
Piece* piece = board[from.x][from.y];
if (piece != NULL)
{
if (!piece->checkValidMove(from,too))
{ throw std::exception("Bad Move");
}
// Other checks.
}
}
class Piece
{
virtual bool checkValidMove(Point const& from,Point const& too) = 0;
};
class Queen: public Piece
{
virtual bool checkValidMove(Point const& from,Point const& too)
{
if (CheckHorizontalMove(from,too) || CheckVerticalMoce(from,too) || CheckDiagonalMove(from,too))
{
.....
}
}
}