Lets say we have the following two class definitions.
#include <iostream>
#include <array>
class A
{
public:
virtual void f() = 0;
};
class B : public A
{
public:
virtual void f() { std::cout << i << std::endl; }
int i;
};
Here sizeof(B) == 8, presumably 4 the virtual pointer and 4 for the int.
Now lets say we make an array of B, like so:
std::array<B, 10> x;
Now we get sizeof(x) == 80.
If my understanding is correct, all method calls on elements of x are resolved statically, as we know the type at compile time. Unless we do something like A* p = &x[i] I don't see a need to even store the virtual pointer.
Is there a way to create an object of type B without a virtual pointer if you know it is not going to be used?
i.e. a template type nonvirtual<T> which does not contain a virtual pointer, and cannot be pointed to by a subtype of T?
Is there a way to create an object of type B without a virtual pointer if you know it is not going to be used?
No. Objects are what they are. A virtual object is virtual, always.
After all, you could do this:
A *a = &x[2];
a->f();
That is perfectly legitimate and legal code. And C++ has to allow it. The type B is virtual, and it has a certain size. You can't make a type be a different type based on where it is used.
Answering my own question here, but I've found that the following does the job, by splitting A into it's virtual and non-virtual components:
enum is_virtual
{
VIRTUAL,
STATIC
};
template <is_virtual X>
class A;
template<>
class A<STATIC>
{
};
template<>
class A<VIRTUAL> : public A<STATIC>
{
public:
virtual void f() = 0;
virtual ~A() {}
};
template <is_virtual X>
class B : public A<X>
{
public:
void f() { std::cout << i << std::endl; }
int i;
};
The important thing here is that in B<> don't specify f() as virtual. That way it will be virtual if the class inherits A<VIRTUAL>, but not virtual if it inherits A<STATIC>. Then we can do the following:
int main()
{
std::cout << sizeof(B<STATIC>) << std::endl; // 4
std::cout << sizeof(B<VIRTUAL>) << std::endl; // 8
std::array<B<STATIC>, 10> x1;
std::array<B<VIRTUAL>, 10> x2;
std::cout << sizeof(x1) << std::endl; // 40
std::cout << sizeof(x2) << std::endl; // 80
}
That would be a nice one to have, but I can't think of any way to revoke virtual members or avoid storing the virtual pointer.
You could probably do some nasty hacks by keeping a buffer that's the size of B without the virtual pointer, and play with casts and such. But is all undefined behavior, and platform dependant.
Unfortunately it won't work in any normal sense as the code inside the method calls expects the virtual pointer to be in the class definition.
I suppose you could copy/paste all of A and B's code into a new class but that gets to be a maintenance headache fast.
Related
I'm trying to figure out why b->boo() actually calls a.far().
is the multiple inheritance from template class and general class forbidden? why does the inherit order matter?
The code is here:
#include <iostream>
template <int somecount>
class inner_parent_class
{
public:
int array[somecount];
virtual void far() = 0;
};
class any_class
{
public:
virtual void boo() = 0;
};
template <int somecount>
class child_class_bad : public inner_parent_class<somecount>, public any_class
{
public:
virtual void boo() override
{
std::cout << "call me" << std::endl;
}
virtual void far() override
{
std::cout << "do not call me" << std::endl;
}
};
template <int somecount>
class child_class_good : public any_class, public inner_parent_class<somecount>
{
public:
virtual void boo() override
{
std::cout << "call me" << std::endl;
}
virtual void far() override
{
std::cout << "do not call me" << std::endl;
}
};
int main()
{
{
child_class_good<32> a;
any_class* b;
auto c = dynamic_cast<void*>(&a);
b = reinterpret_cast<any_class*>(c);
b->boo();
}
{
child_class_bad<32> a;
any_class* b;
auto c = dynamic_cast<void*>(&a);
b = reinterpret_cast<any_class*>(c);
b->boo();
}
return 0;
}
# GCC 9.3.0
# VS 2019 16.5.3
I suppose that both child classes (child_class_good and child_class_bad) are different classes even though their class names are the same, because they are template classes and constructed separately at compiled time. Nevertheless, each class might have its own v-table, so I think calling boo() as their common parent class any_class should correctly work.
reinterpret_cast cannot be used to do what you're trying to do. A reinterpret_cast from a void* to a T* only produces a pointer to a valid T* if the void* pointer it was given was a pointer to an object of type T.
Doing a dynamic_cast<void*>(p) returns a void* which points to the most-derived object pointed to by p. Since your &a is in fact the most-derived object that it points to, it simply converts the pointer to a void*.
Then you perform reinterpret_cast<any_class*> on that void*. The void* points to an object of type child_class_good<32> or child_class_bad<32>. Your cast is saying that the pointer actually points to an any_class. This is incorrect (neither type is standard layout, so the layout of the base classes is not defined), and thus attempting to use the results will yield undefined behavior.
The case that you identify as good is just as invalid as bad; it merely happens to work.
It is not clear why you're trying to do whatever it is you're trying to do, but there's no valid way to take a void* pointing to the most-derived object of an unknown type and casting it to anything useful. In order to use a void*, you have to know the exact type that was used to produce that void*.
The library I am using defines an abstract base class A with ~10 pure virtual methods. There are no non-pure methods publicly defined and I suspect that A has no private data, i.e. the class is merely an interface. The library also defines a few concrete sub-classes of A, such as C.
I would like to add some functionality to A so that all of its sub-classes inherit this functionality. However, A is defined in the library and I cannot do this.
Instead, I have defined a new sub-class of B. This sub-class is not concrete and all of the pure virtual methods of A are left alone. It defines a few new helper methods that call out to the methods defined by A. There are also no fields defined by B.
In order to use B to augment the functionality of instance of C I have done the following, which I suspect is not guaranteed behavior.
Create an object of type C on the heap.
Cast the pointer to this object to instead be of type B*.
Return this pointer, exiting the local scope where the object was created.
Call methods defined by B using this pointer in a different scope.
Is this safe? The objects are created on the heap, so I don't think any slicing will happen. If the safety depends on which fields A and C define, what requirements are needed to guarantee this behavior?
If neither A nor C had their own data other than the vpointer, would this be safe?
What about if only C has its own data?
Edit: I should add that I have attempted this and the behavior has at least seemed to be what I want. I have not profiled for memory leaks though.
The whole thing looks like code smell to me. I would take the approach for B class of a wrapper class: take an A* pointer in the constructor, forwarding the calls you need to that A*. Then you can pass a C* to that constructor, that will be correctly deleted through a "delete" in B destructor.
Here is one idea following up on my comment. It behaves as intended, might be some hidden dangers but to me it seems reasonable as long as bar does not hold any data.
#include <iostream>
struct base {
int x = 1;
int y = 2;
void show() {
std::cout << x + y << std::endl;
}
virtual void virt() = 0;
};
struct foo : base {
int a = 5;
int b = 2;
void print() {
std::cout << a + b << std::endl;
x++;
}
void virt() override {
std::cout << "foo" << std::endl;
}
};
template <typename T>
struct bar : T {
void print2() {
std::cout << T::a * T::b << std::endl;
T::b++;
T::x++;
T::virt();
}
};
template <typename Base>
bar<Base>* extend_with_bar(Base& base) {
return static_cast<bar<Base>*>(&base);
}
int main() {
foo f;
f.show();
f.print();
auto b = extend_with_bar(f);
b->print2();
b->print2();
b->print();
f.print();
b->show();
f.show();
b->virt();
}
I'm using inheritance only for the sake of code reuse, I never cast class to its base class. It is performance heavy program so I would like to avoid the use of virtual functions but I do not know how. Consider following code
class A{
public:
void print(){
std::cout << "Result of f() is: " << f() << std::endl;
}
virtual std::string f(){
return "A";
}
};
class B : public A{
public:
virtual std::string f(){
return "B";
}
};
Would it be somehow possible to not use virtual function for function f() and not to reimplement function print() in the class B? I do not care that A is base class of B I just do not want to write down f() again. Probably inheritance is not the way to go, maybe templates can be used in smart way but I have no idea.
The CRTP pattern is typically used to avoid dynamic dispatch when it can be statically determined what implementation method to call for a particular method.
In your example, both A and B would inherit from a single base class, which provides the print() method. The base class, let's call it Print, is a template whose template argument is a class that provides f(). The twist that earned this pattern the "curious" moniker is that the subclasses must inherit the base class templatized over the subclass. This allows the subclasses to access the base class's print method, but obtaining a version of the base class - and by extension the version of print - that invokes their own f.
Here is an example of working code:
#include <iostream>
template<typename F>
class Print {
public:
void print() {
F& final = static_cast<F&>(*this);
std::cout << "Result of f() is: " << final.f() << std::endl;
}
};
class A: public Print<A> {
public:
std::string f(){
return "A";
}
};
class B: public Print<B> {
public:
std::string f(){
return "B";
}
};
int main() {
A a;
B b;
a.print();
b.print();
}
Although the print implementation is reused among A and B, there are no virtual methods here, nor is there virtual (run-time) dispatch or run-time checks. The one cast present is a static_cast<> whose safety is duly verified by the compiler.
This is possible because for every use of Print<F>, the compiler knows exactly what F is. Thus Print<A>::print is known to invoke A::f, while Print<B>::print invokes B::f, all known at compile time. This enables the compiler to inline and otherwise optimize such calls just like any other non-virtual method calls.
The downside is that there is no inheritance, either. Note that B is not derived from A - if it were, the pattern wouldn't work and both A::print and B::print would print A, since that's what Print<A> outputs. More fundamentally, you cannot pass B* where an A* is expected - that's undefined behavior. In fact, A and B don't share any common superclass, the Parent<A> and Parent<B> classes are completely separate. Loss of run-time dispatch, with both its drawbacks and benefits, and enabling static dispatch instead, is a fundamental tradeoff of static polymorphism.
If, for whatever reason, you do not want the "overhead" of dynamic binding, you can omit the virtual-keyword, which makes the compiler use static binding and disabling polymorphism. That is, the compiler will bind the implementation solely based on the type of the variable at compile time, not at run time.
To be honest, I never were in the situation where I defined a specific implementation for a method in a subclass without enabling polymorphism. Doing so usually indicates that there is no specific behaviour, i.e. the method should not be overridden in the subclass at all.
Further, already the code encapsulating a character constant into a string object costs far more performance then the dynamic binding / vtable-"overhead". Really, rethink it twice and then measure the performance increase before doing such "optimisations".
Anyway, see how your code behaves if you omit virtual. Note that ptr->f() in the code is bound to A::f, because the type of the variable is A*, though it points to an object of type B:
class A{
public:
void print(){
std::cout << "Result of f() is: " << f() << std::endl;
}
std::string f(){
return "A";
}
};
class B : public A{
public:
std::string f(){
return "B";
}
};
int main()
{
A a; cout << a.f(); // -> yields "A"
B b; cout << b.f(); // -> yields "B"
A* ptr = &b; cout << ptr->f(); // -> yields "A"; (virtual f, in contrast) would be "B"
return 0;
}
You could use templates to select dynamic or non-dynamic versions of A and B. A rather tricky/ugly option but worth considering.
#include <string>
template <bool Virt = false>
class A{
public:
std::string f(){
return "A";
}
};
template <>
class A<true> : A<false>{
public:
virtual std::string f(){
return A<false>::f();
}
};
template <bool Virt = false>
class B : public A<Virt>{
public:
std::string f(){
return "B";
}
};
std::string f1() { return B<>().f(); }
std::string f2(A<true> &a) { return a.f(); }
std::string f3() { B<true> b; return f2(b); }
#include <iostream>
int main(){
std::cout << f1() << '\n';
std::cout << f3() << '\n';
return(0);
}
An interesting point to note with this, it would not be possible except for the debatable decision made very early on in C++ (pre-templates) that the virtual keyword should be optional when overriding.
Could anybody explain where c++ compilers keep default values for parameters for virtual functions? I know it is a bad idea to change these parameters in child classes but why?
Thanks.
It's a bad idea because they aren't kept anywhere.
The default values that are used will be those defined in the static (compile-time) type. So if you were to change the default parameters in an override, but you called the function through a base class pointer or reference, the default values in the base would be used.
#include <iostream>
struct Base
{
virtual ~Base(){ }
virtual void foo(int a=0) { std::cout << "base: " << a << std::endl; }
};
struct Derived : public Base
{
virtual ~Derived() { }
virtual void foo(int a=1) { std::cout << "derived: " << a << std::endl; }
};
int main()
{
Base* derived = new Derived();
derived->foo(); // prints "derived: 0"
delete derived;
}
Giving virtual functions default argument initializers tends to defeat polymorphism and introduce unnecessary complexity into a class hierarchy.
consider the following non compliant code
class Thing {
public:
virtual ~Thing();
virtual void doItNTimes( int numTimes = 10 );
virtual void doItThisHigh( double howHigh = 1.0 );
// ...
};
class MyThing : public Thing {
public:
void doItNTimes( int numTimes );
void doItThisHigh( double howHigh = 2.2 );
// ...
};
A default initializer is not part of the type of a function signature and does not participate in overriding or hiding. Therefore both of the base class virtual functions shown in this Non-Compliant Code Example are overridden in the derived class. However, the differences in the status of default argument initializers in the base class and derived class interfaces causes differences in behavior depending on which interface is used to access an object.
MyThing *mt = new MyThing;
Thing *t = mt;
t->doItNTimes(); // default of 10
mt->doItNTimes(); // compile time error!
t->doItThisHigh(); // default of 1.0!
mt->doItThisHigh(); // default of 2.2
In this piece of code, the intention of the designer of the MyThing class is not clear. Presumably, it is important that the default value to doItThisHigh for an object of type MyThing be 2.2. However, it is not clear whether that value should also be used by default when a MyThing is manipulated through its Thing interface.
For more details Please refer the below link https://www.securecoding.cert.org/confluence/display/cplusplus/OOP04-CPP.+Prefer+not+to+give+virtual+functions+default+argument+initializers
I wanted to have confirmation about the following things:
Virtual Mechanism:
I f I have a base class A and it has a Virtual method, then in the derived class generally, we do not include the virtual statement in the function declaration. But what does a virtual mean when included at the dervied class definition.
class A
{
public:
virtual void something();
}
class B:public A
{
public:
virtual void something();
}
Does, that mean that we want to override the method somethign in the classes that derive from the class B?
Also, another question is,
I have a class A, which is derived by three different classes.Now, there is a virtual method anything(), in the base class A.
Now, if I were to add a new default argument to that method in the base class, A::anything(), I need to add it in all the 3 classes too right.
My pick for the answers:
If a method which is virtual in the base class is redefined in the derived class as virtual then we might mean that it shall be overridden in the corresponding derived classes which uses this class as base class.
Yes.If not overriding does not have any meaning.
Pls let me know if what I feel(above 2) are correct.
Thanks,
Pavan Moanr.
The virtual keyword can be omitted on the override in the derived classes. If the overridden function in the base class is virtual, the override is assumed to be virtual as well.
This is well covered in this question: In C++, is a function automatically virtual if it overrides a virtual function?
Your second question is about default values and virtual functions. Basically, each override can have a different default value. However, usually this will not do what you expect it to do, so my advice is: do not mix default values and virtual functions.
Whether the base class function is defaulted or not, is totally independent from whether the derived class function is defaulted.
The basic idea is that the static type will be used to find the default value, if any is defined. For virtual functions, the dynamic type will be used to find the called function.
So when dynamic and static type don't match, unexpected results will follow.
e.g.
#include <iostream>
class A
{
public:
virtual void foo(int n = 1) { std::cout << "A::foo(" << n << ")" << std::endl; }
};
class B : public A
{
public:
virtual void foo(int n = 2) { std::cout << "B::foo(" << n << ")" << std::endl; }
};
int main()
{
A a;
B b;
a.foo(); // prints "A::foo(1)";
b.foo(); // prints "B::foo(2)";
A& ref = b;
ref.foo(); // prints "B::foo(1)";
}
If all your overrides share the same default, another solution is to define an additional function in the base class that does nothing but call the virtual function with the default argument. That is:
class A
{
public:
void defaultFoo() { foo(1); }
virtual void foo(int n) { .... }
};
If your overrides have different defaults, you have two options:
make the defaultFoo() virtual as well, which might result in unexpected results if a derived class overload one but not the other.
do not use defaults, but explicitly state the used value in each call.
I prefer the latter.
It doesn't matter whether you write virtual in derived class or not, it will always be virtual because of the base class, however it is still better to include virtual to explicitly state that it is virtual and then if you accidentally remove that keyword from base class it will give you compiler error (you cannot redefine non-virtual function with a virtual one). EDIT >> sorry, I was wrong. You can redefine non-virtual function with a virtual one however once it's virtual all derived classes' functions with same signature will be virtual too even if you don't write virtual keyword. <<
If you don't redefine virtual function then the definition from base class will be used (as if it were copied verbatim).
If you wish to specify that a virtual function should be redefined in dervied class you should not provide any implementation i.e. virtual void something() = 0;
In this case your class will be an abstract base class (ABC) and no objects can be instantiated from it. If derived class doesn't provide it's own implementetian it will also be an ABC.
I'm not sure what do you mean about default arguments but function signatures should match so all parameters and return values should be the same (it's best to not mix overloading/default arguments with inheritance because you can get very surprising results for example:
class A
{
public:
void f(int x);
};
class B:public A
{
public:
void f(float x);
};
int main() {
B b;
b.f(42); //this will call B::f(float) even though 42 is int
}
Here is a little experiment to test out what you want to know:
class A {
public:
virtual void func( const char* arg = "A's default arg" ) {
cout << "A::func( " << arg << " )" << endl;
}
};
class B : public A {
public:
void func( const char* arg = "B's default arg" ) {
cout << "B::func( " << arg << " )" << endl;
}
};
class C : public B {
public:
void func( const char* arg ) {
cout << "C::func( " << arg << " )" << endl;
}
};
int main(int argc, char* argv[])
{
B* b = new B();
A* b2 = b;
A* c = new C();
b->func();
b2->func();
c->func();
return 0;
}
result:
B::func( B's default arg )
B::func( A's default arg )
C::func( A's default arg )
conclusion:
1- virtual keyword before A's func declaration makes that function virtual in B and C too.
2- The default argument used is the one declared in the class of pointer/reference you are using to access the object.
As someone pointed out, a function in a derived class with the same name and type signature as a virtual function in the base class is automatically always a virtual function.
But your second question about default arguments is interesting. Here is a tool for thinking through the problem...
class A {
public:
virtual void do_stuff_with_defaults(int a = 5, char foo = 'c');
};
is nearly equivalent to this:
class A {
public:
virtual void do_stuff_with_defaults(int a, char foo);
void do_stuff_with_defaults() { // Note lack of virtual keyword
do_stuff_with_defaults(5, 'c'); // Calls virtual function
}
void do_stuff_with_defaults(int a) { // Note lack of virtual keyword
do_stuff_with_defaults(a, 'c'); // Calls virtual functions
}
};
Therefore you are basically having virtual and non-virtual functions with the same name but different type signatures declared in the class if you give your virtual function default arguments.
On way it isn't equivalent has to do with being able to import names from the base class with the using directive. If you declare the default arguments as separate functions, it's possible to import those functions using the using directive. If you simply declare default arguments, it isn't.