Applying “using” keyword on C++ pure virtual function












15















The Class B is overriding the pure Virtual Function "print()" of class A. Class C is inheriting Class B as well as having a "using A::print" statement.
Now why Class C is not an abstract class?



class A {
public :
virtual void print() =0;
};

class B:public A {
public:
void print();
};

void B :: print() {

cout << "nClass B print ()";
}

class C : public B {

public:
using A::print;
};

void funca (A *a) {

// a->print(1);
}

void funcb (B *b) {

b->print();
}

void funcc (C *c) {

c->print();
}

int main() {
B b;
C c;
funca(&c);
funcb(&c);
funcc(&c);
return 0;
}


Output:



    Class B print ()
Class B print ()









share|improve this question

























  • Kinda related, since a using declaration is not an overrider.

    – StoryTeller
    Jan 4 at 12:31
















15















The Class B is overriding the pure Virtual Function "print()" of class A. Class C is inheriting Class B as well as having a "using A::print" statement.
Now why Class C is not an abstract class?



class A {
public :
virtual void print() =0;
};

class B:public A {
public:
void print();
};

void B :: print() {

cout << "nClass B print ()";
}

class C : public B {

public:
using A::print;
};

void funca (A *a) {

// a->print(1);
}

void funcb (B *b) {

b->print();
}

void funcc (C *c) {

c->print();
}

int main() {
B b;
C c;
funca(&c);
funcb(&c);
funcc(&c);
return 0;
}


Output:



    Class B print ()
Class B print ()









share|improve this question

























  • Kinda related, since a using declaration is not an overrider.

    – StoryTeller
    Jan 4 at 12:31














15












15








15








The Class B is overriding the pure Virtual Function "print()" of class A. Class C is inheriting Class B as well as having a "using A::print" statement.
Now why Class C is not an abstract class?



class A {
public :
virtual void print() =0;
};

class B:public A {
public:
void print();
};

void B :: print() {

cout << "nClass B print ()";
}

class C : public B {

public:
using A::print;
};

void funca (A *a) {

// a->print(1);
}

void funcb (B *b) {

b->print();
}

void funcc (C *c) {

c->print();
}

int main() {
B b;
C c;
funca(&c);
funcb(&c);
funcc(&c);
return 0;
}


Output:



    Class B print ()
Class B print ()









share|improve this question
















The Class B is overriding the pure Virtual Function "print()" of class A. Class C is inheriting Class B as well as having a "using A::print" statement.
Now why Class C is not an abstract class?



class A {
public :
virtual void print() =0;
};

class B:public A {
public:
void print();
};

void B :: print() {

cout << "nClass B print ()";
}

class C : public B {

public:
using A::print;
};

void funca (A *a) {

// a->print(1);
}

void funcb (B *b) {

b->print();
}

void funcc (C *c) {

c->print();
}

int main() {
B b;
C c;
funca(&c);
funcb(&c);
funcc(&c);
return 0;
}


Output:



    Class B print ()
Class B print ()






c++ override virtual-functions using-declaration






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 5 at 17:00









curiousguy

4,51622943




4,51622943










asked Jan 4 at 12:21









GtrexGtrex

792




792













  • Kinda related, since a using declaration is not an overrider.

    – StoryTeller
    Jan 4 at 12:31



















  • Kinda related, since a using declaration is not an overrider.

    – StoryTeller
    Jan 4 at 12:31

















Kinda related, since a using declaration is not an overrider.

– StoryTeller
Jan 4 at 12:31





Kinda related, since a using declaration is not an overrider.

– StoryTeller
Jan 4 at 12:31












2 Answers
2






active

oldest

votes


















9














Based on my first attempt to find an answer, @Oliv's comments and answer, let me try to summarize all possible scenarios for a using A::memberFct declaration inside C.





  • A's member function is virtual and overridden by B


  • A's member function is non-virtual and hidden by B


  • A's member function is non-virtual and hidden by C itself


A small example for these cases is as follows.



struct A {
virtual void f() {}
void g() {}
void h() {}
};

struct B : A {
void f() override {}
void g() {}
};

struct C : B {
using A::f; // Virtual function, vtable decides which one is called
using A::g; // A::g was hidden by B::g, but now brought to foreground
using A::h; // A::h is still hidden by C's own implementation
void h() {}
};


Invoking all three functions through C's interface leads to different function calls:



C{}.f(); // calls B::f through vtable
C{}.g(); // calls A::g because of using declarative
C{}.h(); // calls C::h, which has priority over A::h


Note that using declarations inside classes have limited influence, i.e., they change name lookup, but not the virtual dispatch (first case). Whether a member function is pure virtual or not doesn't change this behavior. When a base class function is hidden by a function down the inheritance hierarchy (second case), the lookup is tweaked such that the one subject to the using declaration has precedence. When a base class function is hidden by a function of the class itself (third case), the implementation of the class itself has precedence, see
cppreference:




If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.




In your original snippet, C is hence not an abstract class, as only the lookup mechanism for the member function in question is influenced by the using declarations, and the vtable points doesn't point to the pure virtual member function implementation.






share|improve this answer


























  • That is just wrong, derived class already has a member, means a member first declared in this class. See demo here: godbolt.org/z/ff5cEb

    – Oliv
    Jan 4 at 13:11











  • @Oliv Not sure if I get your point, why does it behave differently then based on the virtualness of the member function in question? If hiding or overriding both leads to an exclusion of the set of declarations introduced by the using declaration, shouldn't it exhibit identical behavior?

    – lubgr
    Jan 4 at 13:37











  • Your right this does not apply too to this case. Neither is the standard paragraph you site...

    – Oliv
    Jan 4 at 14:03











  • I thing I have found the explanation. What do you think of it?

    – Oliv
    Jan 4 at 14:21



















6














This is because using declaration is not a declarations [namespace.udecl]/1, rather it introduces a set of declaration that can be found by qualified name look up:




Each using-declarator in a using-declaration, introduces a set of declarations into the declarative region in which the using-declaration appears. The set of declarations introduced by the using-declarator is found by performing qualified name lookup ([basic.lookup.qual], [class.member.lookup]) for the name in the using-declarator, excluding functions that are hidden as described below.




So a using declaration is not a declaration. It only has influence on the entity(ies) found by qualified name lookup. As such, it does not have influence in the definition of the final overrider [class.virtual]/2:




[...] A virtual member function C::vf of a class object S is a final overrider unless the most derived class ([intro.object]) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf.




Which has a different meaning than: the final overrider is the entity designated by the expression D::vf where D is the most derived class of which S is a base class suboject.



And as a consequence, it does not influence if a class is an abstract class [class.abstract]/4:




A class is abstract if it contains or inherits at least one pure virtual function for which the final overrider is pure virtual.






Note 1:



The consequence is that a using directive will result in different behavior for non virtual and virtual functions [expr.call]/3:




If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called.
Otherwise, its final overrider in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.




Simply:




  • non virtual function => function found by qualified name lookup

  • virtual function => call the final overrider


So if print was not virtual:



class A {
public :
void print() {
std::cout << "n Class A::print()";
}
};

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class A print ()
//Equivalent to:
c.C::print() // Class A::print()
return 0;
}




Note 2:



As some may have noticed in the preceding standard paragraph, it is possible to performe a qualified call of a virtual function to get the non-virtual behavior. So a using declaration of virtual function may be practical (probably a bad practice):



class A {
public :
virtual void print() =0;
};

//Warning arcane: A definition can be provided for pure virtual function
//which is only callable throw qualified name look up. Usualy an attempt
//to call a pure virtual function through qualified name look-up result
//in a link time error (that error message is welcome).
void A::print(){
std::cout << "pure virtual A::print() called!!" << std::endl;
}

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class B print ()
c.C::print() // pure virtual A::print() called!!
//whitout the using declaration this last call would have print "Class B print()"
return 0;
}


Live demo






share|improve this answer


























  • Maybe a comment on how using A::f influences the lookup for a non-virtual, hidden member function f could be helpful? Anyway, great standard-digging!

    – lubgr
    Jan 4 at 14:27













  • @lubgr I did it, the example I give is just pure and probably confusing arcane.

    – Oliv
    Jan 4 at 14:47











  • Ah, sorry for not being clear on this, actually I meant the behavior you linked earlier - If A::print is non-virtual, then using A::print in C does indeed result in a call to A::print through C.

    – lubgr
    Jan 4 at 14:51











  • @lubgr Aahhhhhh!

    – Oliv
    Jan 4 at 15:04











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54038898%2fapplying-using-keyword-on-c-pure-virtual-function%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









9














Based on my first attempt to find an answer, @Oliv's comments and answer, let me try to summarize all possible scenarios for a using A::memberFct declaration inside C.





  • A's member function is virtual and overridden by B


  • A's member function is non-virtual and hidden by B


  • A's member function is non-virtual and hidden by C itself


A small example for these cases is as follows.



struct A {
virtual void f() {}
void g() {}
void h() {}
};

struct B : A {
void f() override {}
void g() {}
};

struct C : B {
using A::f; // Virtual function, vtable decides which one is called
using A::g; // A::g was hidden by B::g, but now brought to foreground
using A::h; // A::h is still hidden by C's own implementation
void h() {}
};


Invoking all three functions through C's interface leads to different function calls:



C{}.f(); // calls B::f through vtable
C{}.g(); // calls A::g because of using declarative
C{}.h(); // calls C::h, which has priority over A::h


Note that using declarations inside classes have limited influence, i.e., they change name lookup, but not the virtual dispatch (first case). Whether a member function is pure virtual or not doesn't change this behavior. When a base class function is hidden by a function down the inheritance hierarchy (second case), the lookup is tweaked such that the one subject to the using declaration has precedence. When a base class function is hidden by a function of the class itself (third case), the implementation of the class itself has precedence, see
cppreference:




If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.




In your original snippet, C is hence not an abstract class, as only the lookup mechanism for the member function in question is influenced by the using declarations, and the vtable points doesn't point to the pure virtual member function implementation.






share|improve this answer


























  • That is just wrong, derived class already has a member, means a member first declared in this class. See demo here: godbolt.org/z/ff5cEb

    – Oliv
    Jan 4 at 13:11











  • @Oliv Not sure if I get your point, why does it behave differently then based on the virtualness of the member function in question? If hiding or overriding both leads to an exclusion of the set of declarations introduced by the using declaration, shouldn't it exhibit identical behavior?

    – lubgr
    Jan 4 at 13:37











  • Your right this does not apply too to this case. Neither is the standard paragraph you site...

    – Oliv
    Jan 4 at 14:03











  • I thing I have found the explanation. What do you think of it?

    – Oliv
    Jan 4 at 14:21
















9














Based on my first attempt to find an answer, @Oliv's comments and answer, let me try to summarize all possible scenarios for a using A::memberFct declaration inside C.





  • A's member function is virtual and overridden by B


  • A's member function is non-virtual and hidden by B


  • A's member function is non-virtual and hidden by C itself


A small example for these cases is as follows.



struct A {
virtual void f() {}
void g() {}
void h() {}
};

struct B : A {
void f() override {}
void g() {}
};

struct C : B {
using A::f; // Virtual function, vtable decides which one is called
using A::g; // A::g was hidden by B::g, but now brought to foreground
using A::h; // A::h is still hidden by C's own implementation
void h() {}
};


Invoking all three functions through C's interface leads to different function calls:



C{}.f(); // calls B::f through vtable
C{}.g(); // calls A::g because of using declarative
C{}.h(); // calls C::h, which has priority over A::h


Note that using declarations inside classes have limited influence, i.e., they change name lookup, but not the virtual dispatch (first case). Whether a member function is pure virtual or not doesn't change this behavior. When a base class function is hidden by a function down the inheritance hierarchy (second case), the lookup is tweaked such that the one subject to the using declaration has precedence. When a base class function is hidden by a function of the class itself (third case), the implementation of the class itself has precedence, see
cppreference:




If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.




In your original snippet, C is hence not an abstract class, as only the lookup mechanism for the member function in question is influenced by the using declarations, and the vtable points doesn't point to the pure virtual member function implementation.






share|improve this answer


























  • That is just wrong, derived class already has a member, means a member first declared in this class. See demo here: godbolt.org/z/ff5cEb

    – Oliv
    Jan 4 at 13:11











  • @Oliv Not sure if I get your point, why does it behave differently then based on the virtualness of the member function in question? If hiding or overriding both leads to an exclusion of the set of declarations introduced by the using declaration, shouldn't it exhibit identical behavior?

    – lubgr
    Jan 4 at 13:37











  • Your right this does not apply too to this case. Neither is the standard paragraph you site...

    – Oliv
    Jan 4 at 14:03











  • I thing I have found the explanation. What do you think of it?

    – Oliv
    Jan 4 at 14:21














9












9








9







Based on my first attempt to find an answer, @Oliv's comments and answer, let me try to summarize all possible scenarios for a using A::memberFct declaration inside C.





  • A's member function is virtual and overridden by B


  • A's member function is non-virtual and hidden by B


  • A's member function is non-virtual and hidden by C itself


A small example for these cases is as follows.



struct A {
virtual void f() {}
void g() {}
void h() {}
};

struct B : A {
void f() override {}
void g() {}
};

struct C : B {
using A::f; // Virtual function, vtable decides which one is called
using A::g; // A::g was hidden by B::g, but now brought to foreground
using A::h; // A::h is still hidden by C's own implementation
void h() {}
};


Invoking all three functions through C's interface leads to different function calls:



C{}.f(); // calls B::f through vtable
C{}.g(); // calls A::g because of using declarative
C{}.h(); // calls C::h, which has priority over A::h


Note that using declarations inside classes have limited influence, i.e., they change name lookup, but not the virtual dispatch (first case). Whether a member function is pure virtual or not doesn't change this behavior. When a base class function is hidden by a function down the inheritance hierarchy (second case), the lookup is tweaked such that the one subject to the using declaration has precedence. When a base class function is hidden by a function of the class itself (third case), the implementation of the class itself has precedence, see
cppreference:




If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.




In your original snippet, C is hence not an abstract class, as only the lookup mechanism for the member function in question is influenced by the using declarations, and the vtable points doesn't point to the pure virtual member function implementation.






share|improve this answer















Based on my first attempt to find an answer, @Oliv's comments and answer, let me try to summarize all possible scenarios for a using A::memberFct declaration inside C.





  • A's member function is virtual and overridden by B


  • A's member function is non-virtual and hidden by B


  • A's member function is non-virtual and hidden by C itself


A small example for these cases is as follows.



struct A {
virtual void f() {}
void g() {}
void h() {}
};

struct B : A {
void f() override {}
void g() {}
};

struct C : B {
using A::f; // Virtual function, vtable decides which one is called
using A::g; // A::g was hidden by B::g, but now brought to foreground
using A::h; // A::h is still hidden by C's own implementation
void h() {}
};


Invoking all three functions through C's interface leads to different function calls:



C{}.f(); // calls B::f through vtable
C{}.g(); // calls A::g because of using declarative
C{}.h(); // calls C::h, which has priority over A::h


Note that using declarations inside classes have limited influence, i.e., they change name lookup, but not the virtual dispatch (first case). Whether a member function is pure virtual or not doesn't change this behavior. When a base class function is hidden by a function down the inheritance hierarchy (second case), the lookup is tweaked such that the one subject to the using declaration has precedence. When a base class function is hidden by a function of the class itself (third case), the implementation of the class itself has precedence, see
cppreference:




If the derived class already has a member with the same name, parameter list, and qualifications, the derived class member hides or overrides (doesn't conflict with) the member that is introduced from the base class.




In your original snippet, C is hence not an abstract class, as only the lookup mechanism for the member function in question is influenced by the using declarations, and the vtable points doesn't point to the pure virtual member function implementation.







share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 4 at 16:46

























answered Jan 4 at 12:26









lubgrlubgr

10.4k21745




10.4k21745













  • That is just wrong, derived class already has a member, means a member first declared in this class. See demo here: godbolt.org/z/ff5cEb

    – Oliv
    Jan 4 at 13:11











  • @Oliv Not sure if I get your point, why does it behave differently then based on the virtualness of the member function in question? If hiding or overriding both leads to an exclusion of the set of declarations introduced by the using declaration, shouldn't it exhibit identical behavior?

    – lubgr
    Jan 4 at 13:37











  • Your right this does not apply too to this case. Neither is the standard paragraph you site...

    – Oliv
    Jan 4 at 14:03











  • I thing I have found the explanation. What do you think of it?

    – Oliv
    Jan 4 at 14:21



















  • That is just wrong, derived class already has a member, means a member first declared in this class. See demo here: godbolt.org/z/ff5cEb

    – Oliv
    Jan 4 at 13:11











  • @Oliv Not sure if I get your point, why does it behave differently then based on the virtualness of the member function in question? If hiding or overriding both leads to an exclusion of the set of declarations introduced by the using declaration, shouldn't it exhibit identical behavior?

    – lubgr
    Jan 4 at 13:37











  • Your right this does not apply too to this case. Neither is the standard paragraph you site...

    – Oliv
    Jan 4 at 14:03











  • I thing I have found the explanation. What do you think of it?

    – Oliv
    Jan 4 at 14:21

















That is just wrong, derived class already has a member, means a member first declared in this class. See demo here: godbolt.org/z/ff5cEb

– Oliv
Jan 4 at 13:11





That is just wrong, derived class already has a member, means a member first declared in this class. See demo here: godbolt.org/z/ff5cEb

– Oliv
Jan 4 at 13:11













@Oliv Not sure if I get your point, why does it behave differently then based on the virtualness of the member function in question? If hiding or overriding both leads to an exclusion of the set of declarations introduced by the using declaration, shouldn't it exhibit identical behavior?

– lubgr
Jan 4 at 13:37





@Oliv Not sure if I get your point, why does it behave differently then based on the virtualness of the member function in question? If hiding or overriding both leads to an exclusion of the set of declarations introduced by the using declaration, shouldn't it exhibit identical behavior?

– lubgr
Jan 4 at 13:37













Your right this does not apply too to this case. Neither is the standard paragraph you site...

– Oliv
Jan 4 at 14:03





Your right this does not apply too to this case. Neither is the standard paragraph you site...

– Oliv
Jan 4 at 14:03













I thing I have found the explanation. What do you think of it?

– Oliv
Jan 4 at 14:21





I thing I have found the explanation. What do you think of it?

– Oliv
Jan 4 at 14:21













6














This is because using declaration is not a declarations [namespace.udecl]/1, rather it introduces a set of declaration that can be found by qualified name look up:




Each using-declarator in a using-declaration, introduces a set of declarations into the declarative region in which the using-declaration appears. The set of declarations introduced by the using-declarator is found by performing qualified name lookup ([basic.lookup.qual], [class.member.lookup]) for the name in the using-declarator, excluding functions that are hidden as described below.




So a using declaration is not a declaration. It only has influence on the entity(ies) found by qualified name lookup. As such, it does not have influence in the definition of the final overrider [class.virtual]/2:




[...] A virtual member function C::vf of a class object S is a final overrider unless the most derived class ([intro.object]) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf.




Which has a different meaning than: the final overrider is the entity designated by the expression D::vf where D is the most derived class of which S is a base class suboject.



And as a consequence, it does not influence if a class is an abstract class [class.abstract]/4:




A class is abstract if it contains or inherits at least one pure virtual function for which the final overrider is pure virtual.






Note 1:



The consequence is that a using directive will result in different behavior for non virtual and virtual functions [expr.call]/3:




If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called.
Otherwise, its final overrider in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.




Simply:




  • non virtual function => function found by qualified name lookup

  • virtual function => call the final overrider


So if print was not virtual:



class A {
public :
void print() {
std::cout << "n Class A::print()";
}
};

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class A print ()
//Equivalent to:
c.C::print() // Class A::print()
return 0;
}




Note 2:



As some may have noticed in the preceding standard paragraph, it is possible to performe a qualified call of a virtual function to get the non-virtual behavior. So a using declaration of virtual function may be practical (probably a bad practice):



class A {
public :
virtual void print() =0;
};

//Warning arcane: A definition can be provided for pure virtual function
//which is only callable throw qualified name look up. Usualy an attempt
//to call a pure virtual function through qualified name look-up result
//in a link time error (that error message is welcome).
void A::print(){
std::cout << "pure virtual A::print() called!!" << std::endl;
}

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class B print ()
c.C::print() // pure virtual A::print() called!!
//whitout the using declaration this last call would have print "Class B print()"
return 0;
}


Live demo






share|improve this answer


























  • Maybe a comment on how using A::f influences the lookup for a non-virtual, hidden member function f could be helpful? Anyway, great standard-digging!

    – lubgr
    Jan 4 at 14:27













  • @lubgr I did it, the example I give is just pure and probably confusing arcane.

    – Oliv
    Jan 4 at 14:47











  • Ah, sorry for not being clear on this, actually I meant the behavior you linked earlier - If A::print is non-virtual, then using A::print in C does indeed result in a call to A::print through C.

    – lubgr
    Jan 4 at 14:51











  • @lubgr Aahhhhhh!

    – Oliv
    Jan 4 at 15:04
















6














This is because using declaration is not a declarations [namespace.udecl]/1, rather it introduces a set of declaration that can be found by qualified name look up:




Each using-declarator in a using-declaration, introduces a set of declarations into the declarative region in which the using-declaration appears. The set of declarations introduced by the using-declarator is found by performing qualified name lookup ([basic.lookup.qual], [class.member.lookup]) for the name in the using-declarator, excluding functions that are hidden as described below.




So a using declaration is not a declaration. It only has influence on the entity(ies) found by qualified name lookup. As such, it does not have influence in the definition of the final overrider [class.virtual]/2:




[...] A virtual member function C::vf of a class object S is a final overrider unless the most derived class ([intro.object]) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf.




Which has a different meaning than: the final overrider is the entity designated by the expression D::vf where D is the most derived class of which S is a base class suboject.



And as a consequence, it does not influence if a class is an abstract class [class.abstract]/4:




A class is abstract if it contains or inherits at least one pure virtual function for which the final overrider is pure virtual.






Note 1:



The consequence is that a using directive will result in different behavior for non virtual and virtual functions [expr.call]/3:




If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called.
Otherwise, its final overrider in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.




Simply:




  • non virtual function => function found by qualified name lookup

  • virtual function => call the final overrider


So if print was not virtual:



class A {
public :
void print() {
std::cout << "n Class A::print()";
}
};

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class A print ()
//Equivalent to:
c.C::print() // Class A::print()
return 0;
}




Note 2:



As some may have noticed in the preceding standard paragraph, it is possible to performe a qualified call of a virtual function to get the non-virtual behavior. So a using declaration of virtual function may be practical (probably a bad practice):



class A {
public :
virtual void print() =0;
};

//Warning arcane: A definition can be provided for pure virtual function
//which is only callable throw qualified name look up. Usualy an attempt
//to call a pure virtual function through qualified name look-up result
//in a link time error (that error message is welcome).
void A::print(){
std::cout << "pure virtual A::print() called!!" << std::endl;
}

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class B print ()
c.C::print() // pure virtual A::print() called!!
//whitout the using declaration this last call would have print "Class B print()"
return 0;
}


Live demo






share|improve this answer


























  • Maybe a comment on how using A::f influences the lookup for a non-virtual, hidden member function f could be helpful? Anyway, great standard-digging!

    – lubgr
    Jan 4 at 14:27













  • @lubgr I did it, the example I give is just pure and probably confusing arcane.

    – Oliv
    Jan 4 at 14:47











  • Ah, sorry for not being clear on this, actually I meant the behavior you linked earlier - If A::print is non-virtual, then using A::print in C does indeed result in a call to A::print through C.

    – lubgr
    Jan 4 at 14:51











  • @lubgr Aahhhhhh!

    – Oliv
    Jan 4 at 15:04














6












6








6







This is because using declaration is not a declarations [namespace.udecl]/1, rather it introduces a set of declaration that can be found by qualified name look up:




Each using-declarator in a using-declaration, introduces a set of declarations into the declarative region in which the using-declaration appears. The set of declarations introduced by the using-declarator is found by performing qualified name lookup ([basic.lookup.qual], [class.member.lookup]) for the name in the using-declarator, excluding functions that are hidden as described below.




So a using declaration is not a declaration. It only has influence on the entity(ies) found by qualified name lookup. As such, it does not have influence in the definition of the final overrider [class.virtual]/2:




[...] A virtual member function C::vf of a class object S is a final overrider unless the most derived class ([intro.object]) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf.




Which has a different meaning than: the final overrider is the entity designated by the expression D::vf where D is the most derived class of which S is a base class suboject.



And as a consequence, it does not influence if a class is an abstract class [class.abstract]/4:




A class is abstract if it contains or inherits at least one pure virtual function for which the final overrider is pure virtual.






Note 1:



The consequence is that a using directive will result in different behavior for non virtual and virtual functions [expr.call]/3:




If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called.
Otherwise, its final overrider in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.




Simply:




  • non virtual function => function found by qualified name lookup

  • virtual function => call the final overrider


So if print was not virtual:



class A {
public :
void print() {
std::cout << "n Class A::print()";
}
};

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class A print ()
//Equivalent to:
c.C::print() // Class A::print()
return 0;
}




Note 2:



As some may have noticed in the preceding standard paragraph, it is possible to performe a qualified call of a virtual function to get the non-virtual behavior. So a using declaration of virtual function may be practical (probably a bad practice):



class A {
public :
virtual void print() =0;
};

//Warning arcane: A definition can be provided for pure virtual function
//which is only callable throw qualified name look up. Usualy an attempt
//to call a pure virtual function through qualified name look-up result
//in a link time error (that error message is welcome).
void A::print(){
std::cout << "pure virtual A::print() called!!" << std::endl;
}

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class B print ()
c.C::print() // pure virtual A::print() called!!
//whitout the using declaration this last call would have print "Class B print()"
return 0;
}


Live demo






share|improve this answer















This is because using declaration is not a declarations [namespace.udecl]/1, rather it introduces a set of declaration that can be found by qualified name look up:




Each using-declarator in a using-declaration, introduces a set of declarations into the declarative region in which the using-declaration appears. The set of declarations introduced by the using-declarator is found by performing qualified name lookup ([basic.lookup.qual], [class.member.lookup]) for the name in the using-declarator, excluding functions that are hidden as described below.




So a using declaration is not a declaration. It only has influence on the entity(ies) found by qualified name lookup. As such, it does not have influence in the definition of the final overrider [class.virtual]/2:




[...] A virtual member function C::vf of a class object S is a final overrider unless the most derived class ([intro.object]) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf.




Which has a different meaning than: the final overrider is the entity designated by the expression D::vf where D is the most derived class of which S is a base class suboject.



And as a consequence, it does not influence if a class is an abstract class [class.abstract]/4:




A class is abstract if it contains or inherits at least one pure virtual function for which the final overrider is pure virtual.






Note 1:



The consequence is that a using directive will result in different behavior for non virtual and virtual functions [expr.call]/3:




If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called.
Otherwise, its final overrider in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.




Simply:




  • non virtual function => function found by qualified name lookup

  • virtual function => call the final overrider


So if print was not virtual:



class A {
public :
void print() {
std::cout << "n Class A::print()";
}
};

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class A print ()
//Equivalent to:
c.C::print() // Class A::print()
return 0;
}




Note 2:



As some may have noticed in the preceding standard paragraph, it is possible to performe a qualified call of a virtual function to get the non-virtual behavior. So a using declaration of virtual function may be practical (probably a bad practice):



class A {
public :
virtual void print() =0;
};

//Warning arcane: A definition can be provided for pure virtual function
//which is only callable throw qualified name look up. Usualy an attempt
//to call a pure virtual function through qualified name look-up result
//in a link time error (that error message is welcome).
void A::print(){
std::cout << "pure virtual A::print() called!!" << std::endl;
}

int main() {
B b;
C c;
b.print() // Class B print ()
c.print() // Class B print ()
c.C::print() // pure virtual A::print() called!!
//whitout the using declaration this last call would have print "Class B print()"
return 0;
}


Live demo







share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 4 at 15:24

























answered Jan 4 at 13:21









OlivOliv

8,6491956




8,6491956













  • Maybe a comment on how using A::f influences the lookup for a non-virtual, hidden member function f could be helpful? Anyway, great standard-digging!

    – lubgr
    Jan 4 at 14:27













  • @lubgr I did it, the example I give is just pure and probably confusing arcane.

    – Oliv
    Jan 4 at 14:47











  • Ah, sorry for not being clear on this, actually I meant the behavior you linked earlier - If A::print is non-virtual, then using A::print in C does indeed result in a call to A::print through C.

    – lubgr
    Jan 4 at 14:51











  • @lubgr Aahhhhhh!

    – Oliv
    Jan 4 at 15:04



















  • Maybe a comment on how using A::f influences the lookup for a non-virtual, hidden member function f could be helpful? Anyway, great standard-digging!

    – lubgr
    Jan 4 at 14:27













  • @lubgr I did it, the example I give is just pure and probably confusing arcane.

    – Oliv
    Jan 4 at 14:47











  • Ah, sorry for not being clear on this, actually I meant the behavior you linked earlier - If A::print is non-virtual, then using A::print in C does indeed result in a call to A::print through C.

    – lubgr
    Jan 4 at 14:51











  • @lubgr Aahhhhhh!

    – Oliv
    Jan 4 at 15:04

















Maybe a comment on how using A::f influences the lookup for a non-virtual, hidden member function f could be helpful? Anyway, great standard-digging!

– lubgr
Jan 4 at 14:27







Maybe a comment on how using A::f influences the lookup for a non-virtual, hidden member function f could be helpful? Anyway, great standard-digging!

– lubgr
Jan 4 at 14:27















@lubgr I did it, the example I give is just pure and probably confusing arcane.

– Oliv
Jan 4 at 14:47





@lubgr I did it, the example I give is just pure and probably confusing arcane.

– Oliv
Jan 4 at 14:47













Ah, sorry for not being clear on this, actually I meant the behavior you linked earlier - If A::print is non-virtual, then using A::print in C does indeed result in a call to A::print through C.

– lubgr
Jan 4 at 14:51





Ah, sorry for not being clear on this, actually I meant the behavior you linked earlier - If A::print is non-virtual, then using A::print in C does indeed result in a call to A::print through C.

– lubgr
Jan 4 at 14:51













@lubgr Aahhhhhh!

– Oliv
Jan 4 at 15:04





@lubgr Aahhhhhh!

– Oliv
Jan 4 at 15:04


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54038898%2fapplying-using-keyword-on-c-pure-virtual-function%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

MongoDB - Not Authorized To Execute Command

How to fix TextFormField cause rebuild widget in Flutter

in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith