Using VC71 compiler and get compiler errors, that i don't understand.
Here comes the example
class A
{
public:
virtual int& myMethod() = 0;
virtual const int& myMethod()const = 0;
};
class B: public A
{
public:
// generates: error C3241: 'const int &B::myMethod(void)' : this method was not introduced by 'A'
virtual int& A::myMethod();
// error C2555: 'B::myMethod': overriding virtual function return type differs and is not covariant from 'A::myMethod'
virtual const int& A::myMethod() const;
};
when i switch order of both method definitions in B then I see a different compiler error:
class B: public A
{
public:
// error C3241: 'const int &B::myMethod(void)' : this method was not introduced by 'A'
virtual const int& A::myMethod() const;
// error C2556: 'int &B::myMethod(void)' : overloaded function differs only by return type from 'const int &B::myMethod(void)'
// error C2373: 'B::myMethod' : redefinition; different type modifiers
virtual int& A::myMethod();
// error C2555: 'B::myMethod': overriding virtual function return type differs and is not covariant from 'A::myMethod'
};
however, if I omit the A:: stuff then i don't get any compiler error:
class B: public A
{
public:
virtual int& myMethod();
virtual const int& myMethod() const;
};
So, what exactly does A:: in front of my method names and why do i see these diverse compiler errors? Any explanation welcome!
class B: public A
{
public:
virtual const int& myMethod() const;
virtual int& myMethod();
};
Remove the A:: in B's definition, and it works well :)
EDIT: missed something in the question...
The :: is used to indicate the scope. You use it either with namespaces or classes to explicitly qualify where to look for the symbol afterwards.
Used in conjunction with methods, it means that you want to precise which method calls, for example:
struct A { int getInt(); }
struct B: public A { int getInt(); }
B b;
b.A::getInt(); // calls A::getInt, not B::getInt
This is completely out of order for a method declaration, the method is declared within a scope and naturally belongs to this scope:
namespace foo
{
int bar(); // full name is foo::bar
}
struct Foo
{
static int bar(); // full name is Foo::bar
};
However, it's useful when referring to the mode:
using foo::bar;
int a = bar(); // calls foo::bar because we asked the compiler
// to import it in the current scope
Or as we already seen, to directly invoke the method:
int B::getInt() // definition outside the class
// we need to specify what we define
{
return this->A::getInt() + 1; // call A::getInt, without precising it
// we would have a stack overflow
}
Hope this helps.
The A:: signifies that you're calling a function from A. Here's an example of why you'd want to use A::
class A{
public:
int m_val;
};
class B{
public:
int m_val;
};
class C: public A, public B{}
Now when I want to set a value for m_val in C, I'd have to do:
C myC;
myC::A::m_val = 4;
so that the compiler doesn't get confused as between what variable you are accessing.
You're not supposed to scope function declarations inside a class declaration. Error messages are not specified in the C++ standard. So, each compiler will obviously produce different messages for something this bizarre.
I assume you're doing something like this to handle multiple inheritance, i.e:
class A
{
public:
virtual int& myMethod() = 0;
};
class A2
{
public:
virtual int& myMethod() = 0;
};
class B: public A, public A2
{
public:
virtual int& A::myMethod();
virtual int& A2::myMethod();
};
But it doesn't work that way. B can only have one myMethod(). See here:
http://www.cprogramming.com/tutorial/multiple_inheritance.html
It looks to me as though you've tried moving a .cpp file contents into a .h file? Those scope declarations would make sense in the .cpp definition file, but shouldn't be there in the .h declaration (as others have alrady pointed out).
// generates: error C3241: 'const int &B::myMethod(void)' : this method was not introduced by 'A'
virtual int& A::myMethod();
So here you're saying you're using a virtual function which is implementing an interface function which is defined elsewhere. By putting A:: in front of it you're saying that your function is overriding myMethod which is defined in A. If you had two base classes (B and C for arguments sake) which both have a function with the same name, you might use virtual B::ThatFunction() to override B's imlpementation or virtual C::ThatFunction() to override C's implementation.
Removing all the A::'s in the A class will fix your compile problems.
Related
This question already has an answer here:
method in the derived class got executed without a *virtual* keyword in the referred class
(1 answer)
Closed 2 years ago.
Probably, i misunderstood c++ polymorphism(virtual function).
Please point me what i miss.
the source code is below
#include <iostream>
using namespace std;
class A {
public:
virtual void print(void) {
cout<<"class A"<<endl;
}
};
class B : public A {
public:
void print(void) {
cout<<"class B"<<endl;
}
};
class C : public B {
public:
void print(void) {
cout<<"class C"<<endl;
}
};
int main() {
A a;
B b;
C c;
A *pAa = &a;
A *pAb = &b;
A *pAc = &c;
B *pBc = &c;
pAa->print();
pAb->print();
pAc->print();
pBc->print(); // shouldn't be "class B"
return 0;
}
result
------------------------------
class A
class B
class C
class C // shouldn't be "class B"
my understanding is that
the last print statement should print "class B"
because pBc is a pointer of class B and the print function in class B is non virtual member function. i could not find the answer about this situation.
please tell me why or point me where i can find the answer and
understand c++ polymorphism in comprehension.
thanks.
If a function with a given signature is declared as virtual in a top-level base class, then the function is virtual in all derived classes no matter if it is marked with the keyword virtual (override, final) or not:
virtual function specifier
Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration)
struct Base {
// Pure virtual function.
virtual void foo() const = 0;
};
struct A : public Base {
// Overriding virtual function, even if it
// is not marked as virtual (override, or final).
void foo() const {}
};
In A, adding the virtual specifier to foo() would only bring semantic value; it will be no functional difference whether virtual is omitted or not (unless someone changes the interface in Base).
Many static analyzers enforce(1) marking derived virtual functions with override or final, for two reasons:
semantics; clearly showing the given function is a virtual function (as per being defined so higher up in the inheritance chain), and
enforcement; if a function is marked as override and final but is not actually an overriding function, you will get a compiler error, which can be particularly useful to protect against mistakes when changing a base class interface (whilst forgetting which classes that actually implements this interface).
E.g.:
struct Base {
// Pure virtual function.
virtual void foo() const = 0;
};
struct A : public Base {
// Overriding virtual function.
void foo() const override {}
};
struct B final : public Base {
// Overriding (final) virtual function.
void foo() const final {}
// Error: Function does not override.
// void bar() const override {}
};
(1) E.g. Rule A10-3-1 in the Autsar C++14 Language Guidelines (safety-critical development in automotive) is categorized as a required rule: Virtual function declaration shall contain exactly one of the three specifiers:(1) virtual, (2) override, (3) final.
the print function in class B is non virtual member function
No. Since A::print is marked as virtual and B inherits from A, then B::print is virtual too; regardless of the keywork virtual is specified on it or not.
(emphasis mine)
If some member function vf is declared as virtual in a class Base, and
some class Derived, which is derived, directly or indirectly, from
Base, has a declaration for member function with the same
name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers
Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration) and overrides Base::vf (whether or not the word override is used in its declaration).
Forgive the obscure title. It's likely a duplicate but I couldn't find the correct phrase.
Consider the following inheritance hierarchy.
class A
{
public:
virtual void Foo(int i) { printf("A::Foo(int i)\n"); }
void Foo(int a, int b) { Foo(a + b); }
};
class B : public A
{
public:
void Foo(int i) override { printf("B::Foo(int i)\n"); }
};
class C : public B
{
public:
void Bar() { Foo(1, 2); } //error C2660: function does not take two arguments
};
A has two methods named Foo with a different number of parameters. Only one of them is virtual.
B overrides the virtual method.
C tries to call the non-virtual method and encounters an error.
Calling the method as A::Foo(1, 2) does work fine.
Question:
Why can't the compiler deduce that the correct method is found on A?
It seems odd we would have to explicitly add A:: in a call such as:
C c;
c.A::Foo(1, 2);
Because the member function named Foo is found at the class scope of B, and then name lookup stops, so the Foo in class A is not visible, and won't be considered for overload resolution, even if the version in class A is more appropriate. It is name hiding.
You can use using to introduce them into the same scope, and make overload resolution work as you expect. Such as:
class C : public B
{
using A::Foo;
using B::Foo;
public:
void Bar() { Foo(1, 2); }
};
See Unqualified name lookup
LIVE
When I tried to compile next construction I have got the error: cannot convert parameter 1 from 'std::vector<_Ty>' to 'float'
Why dose it happen?
class A
{
public:
virtual int action(float)
{return 5;}
virtual int action(std::vector<float>)
{return 10;}
};
class B : public A
{
public:
int action(float) override
{return 6;}
};
class C : public B
{
public:
int action(std::vector<float>) override
{
B::action(std::vector<float>());
return 7;
}
};
int main()
{
C instance;
int temp = instance.action(std::vector<float>());
getchar();
return 0;
}
When the compiler sees a function call
B::action(std::vector<float>());
It needs two steps to decide which function call needs to be made. In the first step it looks up the name action. If the lookup results in one or more functions, it stops the lookup. It does not lookup the overloaded functions in base classes. If the lookup results in multiple function names, it tries overload resolution.
In your case, the lookup results in only one function - int B::action(float). The lookup stops there. However, that function does not match the argument being used. Hence, the compiler reports it as an error.
I can think of the following ways to resolve the problem.
Make all overloads of A::action available for lookup in B
class B : public A
{
public:
using A::action;
int action(float) override
{return 6;}
};
Change the call so it uses A::action(float)
class C : public B
{
public:
int action(std::vector<float>) override
{
A::action(std::vector<float>());
return 7;
}
};
I strongly recommend using the first approach.
The compiler does not search for overloads in parent classes if the derived class declares a function by the same name. Typically, if you've enabled warnings, the compiler would warn something like:
warning: 'C::action' hides overloaded virtual function [-Woverloaded-virtual]
If you specify the scope where the overload is declared, the call will work:
A::action(std::vector<float>());
But more generally, you should always avoid overloading virtual functions.
This has the feeling of a complete newbie question, but why does the following code not compile when the final specifier is used for B::operator()?
struct A
{
virtual void operator()() const = 0;
};
// the CRTP-component is not really necessary here
// but it possibly makes more sense in that it could be applied like this in reality
//
template<typename Derived>
struct B : A
{
virtual void operator()() const override final
{
static_cast<Derived const&>(*this).operator()();
}
};
struct C : B<C>
{
void operator()() const
{
//do something
}
};
int main()
{
C()();
}
G++ prints the following error message:
main.cpp:17:14: error: virtual function 'virtual void C::operator()() const'
void operator()() const
^
main.cpp:9:22: error: overriding final function 'void B<Derived>::operator()() const [with Derived = C]'
virtual void operator()() const override final
^
I would have thought it works as the non-virtual C::operator() does not override the virtual functions in its base classes? How can I bring this to work (--without changing the name of C::operator())?
EDIT: As pointed out by several users, the answer is simply that the virtual-keyword in the derived class is redundant (whereas I thought leaving it out would prevent from inheriting). However, the goal I had in asking this -- namely a consistent interface throughout the dynamic and static inheritance hierarchy -- can be solved by using a non-virtual operator[] throughout and couple classes A and B by a virtual function apply:
struct A
{
void operator()() const
{
this->apply();
}
protected:
virtual void apply() const = 0;
};
template<typename Derived>
struct B : A
{
void operator()() const
{
static_cast<Derived const&>(*this).operator()();
}
protected:
virtual void apply() const override final
{
this->operator()();
}
};
struct C : B<C>
{
void operator()() const
{
//do something
}
};
int main()
{
C()();
}
If a function is declared virtual in a base class, then a function declared with the same name and parameter list is implicitly virtual in derived classes, whether or not you use the virtual keyword. You cannot make C::operator()() non-virtual.
A function in a derived class with the same signature as a virtual function in a base class overrides that virtual function from the base class. That makes it a virtual function, even if/though the declaration in the derived class doesn't use the virtual key word.
That can't be changed, so if you really need to have a function with the same name in a derived class that doesn't override the virtual function from the base class (and in the process, become virtual itself and in this case, violate the final in B) you'll need to change the signature of the function in the derived class. That can mean a different name, different parameter list, or different qualifiers. I'd treat the latter two with extreme caution though--the compiler will be able to sort out the mess you've made, but many human readers may (very easily) be surprised.
If I were reviewing such code, I'd probably cite this as a problem, and the author would need to provide very solid reasoning for why it was truly necessary to get it approved.
As an override (because it has the same signature as the virtual function in a base class), the override conflicts with the final specified in its base class.
One fix (or rather workaround) is to give that function a defaulted argument, so that it has a different type and hence not an override, and a better approach is to fix the design.
If I have a code like this:
struct A {
virtual void f(int) {}
virtual void f(void*) {}
};
struct B : public A {
void f(int) {}
};
struct C : public B {
void f(void*) {}
};
int main() {
C c;
c.f(1);
return 0;
}
I get an error that says that I am trying to do an invalid conversion from int to void*. Why can't compiler figure out that he has to call B::f, since both functions are declared as virtual?
After reading jalf's answer I went and reduced it even further. This one does not work as well. Not very intuitive.
struct A {
virtual void f(int) {}
};
struct B : public A {
void f(void*) {}
};
int main() {
B b;
b.f(1);
return 0;
}
The short answer is "because that's how overload resolution works in C++".
The compiler searches for functions F inside the C class, and if it finds any, it stops the search, and tries to pick a candidate among those. It only looks inside base classes if no matching functions were found in the derived class.
However, you can explicitly introduce the base class functions into the derived class' namespace:
struct C : public B {
void f(void*) {}
using B::f; // Add B's f function to C's namespace, allowing it to participate in overload resolution
};
Or you could do this:
void main()
{
A *a = new C();
a->f(1); //This will call f(int) from B(Polymorphism)
}
Well I think first of all you did not understand what virtual mechanism or polymorhism. When the polymorphism is achieved only by using object pointers. I think you are new to c++. Without using object pointers then there is no meaning of polymorphism or virtual keyword use base class pointer and assign the desired derived class objects to it. Then call and try it.