gcc misses a "hidden overloaded virtual function" warning - gcc

I accidentally removed a const qualifier from a derived class implementation of a virtual method. I usually use clang which issues a warning about that. When I switched to gcc with Wall the thing goes completely unnoticed. Why is that? Here is my file:
$ cat main.cpp
#include <iostream>
class Father {
public:
virtual int get() const { return 8; }
};
class Son : public Father {
public:
virtual int get() /* const */ { return 6; }
};
int main(int argc, char **argv)
{
Father *f = new Son;
std::cout << f->get() << "\n";
return 0;
}
And here are the compilation outputs for gcc and clang:
$ clang++ -Wall main.cpp -o main
main.cpp:10:14: warning: 'Son::get' hides overloaded virtual function
[-Woverloaded-virtual]
virtual int get() /* const */ { return 6; }
^
main.cpp:5:14: note: hidden overloaded virtual function 'Father::get' declared
here: different qualifiers ('const' vs unqualified)
virtual int get() const { return 8; }
^
1 warning generated.
And
$ g++ -Wall main.cpp -o main
$ ./main
8

Related

Find a unique_ptr to an inherited class object emplaced_back in a vector

I am trying to implement an Entity Component System (ECS) for my game. I have a base class "Component" (referred here as A) which is inherited by child class like HealthComponent(referred here as B), DamageComponent (referred here C)
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
class A
{
public:
A() : VarA(10){}
int VarA;
const std::string ClassName = "A";
virtual void prnt(){ std::cout << "A class" << std::endl; }
};
class B : public A
{
public:
B() : VarB(20){}
int VarB;
const std::string ClassName = "B";
void prnt(){ std::cout << "B class" << std::endl; }
bool operator== (const B& other) const
{
return this->ClassName == other.ClassName;
}
};
class C : public A
{
public:
C() : VarC(30){}
int VarC;
const std::string ClassName = "C";
void prnt(){ std::cout << "C class" << std::endl; }
bool operator== (const B& other) const
{
return this->ClassName == other.ClassName;
}
};
int main()
{
std::vector<std::unique_ptr<A>> ObjVector;
std::vector<std::unique_ptr<A>>::iterator ObjIterator;
A* object1 = new B();
std::unique_ptr<A> bptr{object1};
ObjVector.emplace_back(std::move(bptr));
A* object2 = new C();
std::unique_ptr<A> cptr{object2};
ObjVector.emplace_back(std::move(cptr));
ObjIterator = std::find(ObjVector.begin(), ObjVector.end(), B);
return 0;
}
on compiling the code
-------------- Build: Debug in STL (compiler: GNU GCC Compiler)---------------
x86_64-w64-mingw32-g++.exe -Wall -g -std=c++11 -c C:\Users\admin\Desktop\code\C++\STL\main.cpp -o obj\Debug\main.o
x86_64-w64-mingw32-g++.exe -o bin\Debug\STL.exe obj\Debug\main.o
C:\Users\admin\Desktop\code\C++\STL\main.cpp: In function 'int main()':
C:\Users\admin\Desktop\code\C++\STL\main.cpp:58:66: error: expected primary-expression before ')' token
58 | ObjIterator = std::find(ObjVector.begin(), ObjVector.end(), B);
| ^
I tried using "new B()" and "(&B)" as the last parameter in std::find function but it still gave me errors. Please Help.
UPDATED CODE
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
class A
{
public:
A() : VarA(10){}
int VarA;
const std::string ClassName = "A";
virtual std::string getClassName(){ return ClassName; }
};
class B : public A
{
public:
B() : VarB(20){}
int VarB;
const std::string ClassName = "B";
std::string getClassName() override { return ClassName; }
};
class C : public A
{
public:
C() : VarC(30){}
int VarC;
const std::string ClassName = "C";
std::string getClassName() override { return ClassName; }
};
int main()
{
std::vector<std::unique_ptr<A>> ObjVector;
std::vector<std::unique_ptr<A>>::iterator ObjIterator;
A* object1 = new B();
std::unique_ptr<A> bptr{object1};
ObjVector.emplace_back(std::move(bptr));
A* object2 = new C();
std::unique_ptr<A> cptr{object2};
ObjVector.emplace_back(std::move(cptr));
ObjIterator = std::find_if(ObjVector.begin(), ObjVector.end(),
[](const std::unique_ptr<A>& p)
{
return dynamic_cast<B*>(p.get()) != nullptr;
});
std::cout << (*ObjIterator)->VarB << std::endl;
return 0;
}
Your solution worked and i changed some of the code accordingly. It gives me access to methods common to all class, here "getClassName()". But on accessing class specific methods and variables (here VarB, which is specific to class B) it gives me the following error
-------------- Build: Debug in STL (compiler: GNU GCC Compiler)---------------
x86_64-w64-mingw32-g++.exe -Wall -g -std=c++11 -c C:\Users\admin\Desktop\code\C++\STL\main.cpp -o obj\Debug\main.o
x86_64-w64-mingw32-g++.exe -o bin\Debug\STL.exe obj\Debug\main.o
C:\Users\admin\Desktop\code\C++\STL\main.cpp: In function 'int main()':
C:\Users\admin\Desktop\code\C++\STL\main.cpp:55:34: error: 'class A' has no member named 'VarB'; did you mean 'VarA'?
55 | std::cout << (*ObjIterator)->VarB << std::endl;
| ^~~~
| VarA
Basically I cannot access the methods and variables that are not included in the base class. What am I doing wrong here?

Failed to understand (and fix) why this warning "call of overload xxx is ambiguous" exists

I'm stuck in fixing this gcc warning : I got tree version of the method "registerCalBack", each of them takes a different "callable" introduced through std::function. Depending on various callable type I declare, I can compile or not, gcc issuing a warning "call of overloaded registerCallBackxxxxx is ambiguous".
I know overloading can be resolved by compiler considering arguments, and not return type, but in that case I failed to understand why gcc is seeing ambiguity : to me, each TCallBack... I defined are different in their argument, and when I change return type of the third one, it compiles... this is really confusing me. I guess part of the problem comes from the fact some parameters are actually incomplete type, but this is how they are accessible from SDL headers, so I reproduced it the example I provide in this thread.
In comment in the code you got examples of definitions that compiled and other that not.
I hope some of you will understand better than me, right now I do not know where to look. Many thanks in advance.
here the gcc command line to compile:
-pedantic -W -Wall -Wextra -std=c++2a -Weffc++ -Wfatal-errors -Winit-self -Wnon-virtual-dtor -Winline -Wmissing-declarations -Wunreachable-code -Wshadow -Wswitch-enum -fstack-protector -Wstack-protector -O0
P.
#include <iostream>
#include <functional>
//This is how SDL_Renderer and SDL_Texture are declared in SDL.h, as incomplete type declaration, to make it opaque
//I reproduce it here with other name, to avoid the need to install SDL if you want to test
struct RENDERER;
typedef struct RENDERER RENDERER;
struct TEXTURE;
typedef struct TEXTURE TEXTURE;
//this is stupid, just to make test
struct dumb;
typedef struct dumb dumb;
class ClassUsingCallBacks // an instance of this class will use callbacks
{
public:
typedef std::function < RENDERER* (void) > TCallBack_GetRenderer;
typedef std::function < TEXTURE* (const std::string&) > TCallBack_GetTexture;
//this works:
// typedef std::function < dumb* (void) >
// typedef std::function < dumb* (TEXTURE*) >
// typedef std::function < int (TEXTURE*) >
// typedef std::function < TEXTURE* (TEXTURE*) >
// BUT THIS FAILED TO COMPILE :
// typdef std::function < void (TEXTURE*) >
// typdef std::function < void* (TEXTURE*) >
// typedef std::function < void (const std::string&, int, int, int)
typedef std::function < void (TEXTURE*) > TCallBack_removeTexture;
virtual ~ClassUsingCallBacks() {};
void registerCallBack(TCallBack_GetRenderer cb) {
std::cout << "Register a TCallBack_GetRenderer" << std::endl;
getRenderer = cb;
}
void registerCallBack(TCallBack_GetTexture cb) {
std::cout << "Register a TCallBack_GetTexture" << std::endl;
getTexture = cb;
}
void registerCallBack(TCallBack_removeTexture cb) {
std::cout << "Register a TCallBack_removeTexture" << std::endl;
removeTexture = cb;
}
//to test registered callbacks
void makeCalls(void) {
if (getRenderer) getRenderer();
if (getTexture) getTexture("a name");
//not this one since it's the one we failed to implement :/
// if (removeTexture) removeTexture();
}
protected:
TCallBack_GetRenderer getRenderer {};
TCallBack_GetTexture getTexture {};
TCallBack_removeTexture removeTexture {};
};
class ClassWithCallBacks
{
public:
virtual ~ClassWithCallBacks() {};
RENDERER* getRenderer(void) {
std::cout << "Inside getRenderer" << std::endl;
return nullptr;
}
TEXTURE* getTexture(const std::string& s) {
(void)s;
std::cout << "Inside getTexture" << std::endl;
return nullptr;
}
void removeTexture(TEXTURE* t) {
(void)t;
std::cout << "Inside removeTexture" << std::endl;
}
};
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
std::cout << "entering main" << std::endl;
ClassWithCallBacks calledObject;
ClassUsingCallBacks user;
auto cb_1 = std::bind(&ClassWithCallBacks::getRenderer, calledObject);
user.registerCallBack(cb_1);
auto cb_2 = std::bind(&ClassWithCallBacks::getTexture, calledObject, std::placeholders::_1);
user.registerCallBack(cb_2);
user.makeCalls();
std::cout << "Leaving main" << std::endl;
return 0;
}
std::bind produces a callable object that takes arbitrary number of arguments, and simply discards those that don't need to be forwarded to the bound callable.
std::function<void(Something)> accepts a callable that returns a result, then simply discards this result.
Therefore, cb_1 can be accepted by both std::function<RENDERER* (void)> and std::function<void (TEXTURE*)>. It can take (and ignore) TEXTURE* parameter, and the function can ignore its return value.
Fundamentally, you are relying heavily on type erasure, but then hoping that the types you are erasing would nevertheless help guide overload resolution. Personally, I would have given the three registerXXX functions different names, reflecting the kind of callback they are registering. No overloading, no problem.

g++ compiler optimization: cannot convert ‘<brace-enclosed initializer list>’

Following code not compiling:
A.h
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
namespace net {
using Ip = in_addr_t;
using Port = in_port_t;
using SockFd = int;
class Params final {
public:
Ip getIp() const { return ip_; }
Port getPort() const { return port_; }
private:
Ip ip_ {INADDR_ANY};
Port port_ {htons(5)};
};
}
A.cpp
#include <iostream>
#include "A.h"
int main(){
net::Params a {};
std::cout << "Ip=" << a.getIp() << ", Port=" << a.getPort() << std::endl;
return 0;
}
Compilation:
g++-6 -O2 -std=c++11 A.cpp
Error:
In file included from /usr/include/x86_64-linux-gnu/bits/byteswap.h:35:0,
from /usr/include/endian.h:60,
from /usr/include/ctype.h:39,
from /usr/include/c++/6/cctype:42,
from /usr/include/c++/6/bits/localefwd.h:42,
from /usr/include/c++/6/ios:41,
from /usr/include/c++/6/ostream:38,
from /usr/include/c++/6/iostream:39,
from A.cpp:1:
A.h:21:15: error: statement-expressions are not allowed outside functions nor in template-argument lists
Port port_ {htons(5)};
^
In file included from A.cpp:3:0:
A.h:21:23: error: cannot convert ‘<brace-enclosed initializer list>’ to ‘net::Port {aka short unsigned int}’ in initialization
Port port_ {htons(5)};
^
But when I change port_ member variable initialization to: Port port_ {5};, g++ with -O2 compiles fine.
Above code compiles fine without optimization flag, whether port_ initialized as: Port port_ {htons(5)}; or as Port port_ {5};
Whats wrong?
Seems to be a ompiler and/or libstd bug. The compiler tries to optimize away the function call to htons with some macros and compiler magic. That results in some problem I do not understand. But you can define an inline function myhtons that calls htons and use that instead. Works for me with gcc 7.2.
inline Port myhtons( Port v )
{
return htons(v);
}
class Params final {
public:
Ip getIp() const { return ip_; }
Port getPort() const { return port_; }
private:
Ip ip_ {INADDR_ANY};
Port port_ { myhtons(5) };
};

How can I remove the warning that my iterator has a non-virtual destructor when extending boost::iterator_facade?

When compiling with -Weffc++ and extending boost::iterator_facade, I get the compiler warning: base class has a non-virtual destructor. What can I do to fix this?
Here is sample code:
#include <iostream>
#include <boost/iterator/iterator_facade.hpp>
struct my_struct_t {
int my_int;
my_struct_t() : my_int(0) {
}
};
class my_iterator_t : public boost::iterator_facade<
my_iterator_t,
my_struct_t const,
boost::forward_traversal_tag
> {
private:
friend class boost::iterator_core_access;
my_struct_t my_struct;
public:
my_iterator_t() : my_struct() {
}
void increment() {
++ my_struct.my_int;
}
bool equal(my_iterator_t const& other) const {
return this->my_struct.my_int == other.my_struct.my_int;
}
my_struct_t const& dereference() const {
return my_struct;
}
};
int main() {
my_iterator_t my_iterator;
std::cout << my_iterator->my_int << "\n";
++my_iterator;
std::cout << my_iterator->my_int << "\n";
return 0;
}
I compile on Fedora 19 like this:
$ g++ test.cpp -std=gnu++0x -Weffc++ -o test
Here is the actual warning:
g++ test.cpp -std=gnu++0x -Weffc++ -o test
test.cpp:10:7: warning: base class ‘class boost::iterator_facade<my_iterator_t, const my_struct_t, boost::forward_traversal_tag>’ has a non-virtual destructor [-Weffc++]
class my_iterator_t : public boost::iterator_facade<
^
Thanks.
-Weffc++ option enables warnings about violations of the some style guidelines from Scott Meyers’ Effective C++ book. Your code violates the Item 7: Make destructors virtual in polymorphic base classes. So the compiler isn't complaining about your iterator, it's about the base class: boost::iterator_facade. I don't think you can eliminate the warning by modify your own code. As to why virtual destructor in polymorphic base classes are so important, a good answer is here.

can't use static std::atomic (and don't know how to initialize it)

I have the following code:
#include <cstdlib>
#include <cstdio>
#include <atomic>
enum ATYPE { Undefined = 0, typeA, typeB, typeC };
template<ATYPE TYPE = Undefined>
struct Object
{
Object() { counter++; }
static std::atomic<int> counter;
};
//template<ATYPE TYPE>
//std::atomic<int> Object<TYPE>::counter = 0;
template<ATYPE TYPE>
void test()
{
printf("in test\n");
Object<TYPE> o;
}
int main(int argc, char **argv)
{
test<typeA>();
printf("%d\n", Object<typeA>::counter.load());
return 0;
}
and when I compile it with the following command line:
clang++ -o test -std=c++11 -stdlib=libc++ test.cpp
I got the following error:
Undefined symbols for architecture x86_64:
"Object<(ATYPE)1>::counter", referenced from:
_main in testray-D4iTOH.o
Object<(ATYPE)1>::Object() in testray-D4iTOH.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I have no idea if what I am trying to do is technically possible. As the code hopefully shows, I am trying to create a static instance of the atomic class (BTW, I have no idea how to initialize this variable either. How do you intialize a static std::atomic<>?). What I am trying to do is count the number of instances of the class Object created while running the program, for each possible type (typeA, B, C, etc.).
That's the mechanism I came up with but maybe (beside the problem I have which I would like to fix if possible) someone could advice a better solution? It would be much appreciated.
Thank you so much.
As pointed by Dave in the comment, the static variable needs to be declared somewhere:
include
#include <cstdio>
#include <atomic>
enum ATYPE { Undefined = 0, typeA, typeB, typeC };
template<ATYPE TYPE = Undefined>
struct Object
{
Object() { counter++; }
static std::atomic<int> counter;
};
template<ATYPE TYPE>
std::atomic<int> Object<TYPE>::counter(0);
template<ATYPE TYPE>
void test()
{
printf("in test\n");
Object<TYPE> o;
}
int main(int argc, char **argv)
{
test<typeA>();
printf("%d\n", Object<typeA>::counter.load());
return 0;
}
It compiles fine.

Resources