Consider the problem of getting an object as argument and printing its type:
#include <iostream>
class A { };
class B : public A { };
class C : public A { };
class D : public C, public B { };
using namespace std;
template<class T>
void print_type(T* info)
{
if(dynamic_cast<D*>(info))
cout << "D" << endl;
else if(dynamic_cast<C*> (info))
cout << "C" << endl;
else if(dynamic_cast<B*>(info))
cout << "B" << endl;
else if(dynamic_cast<A*> (info))
cout << "A" << endl;
}
int main(int argc, char** argv)
{
D d;
print_type(&d);
return 0;
}
It gives me the following error: "Ambiguous conversion from derived class 'D' to base class."
But I fail to see where's the ambiguity: if the object declared in main (d) is of type D, why can't be it directly converted to a type A?
Also, if I pass an argument of type string of course I get other errors:
'std::basic_string<char>' is not polymorphic
In Java for generics there is the syntax: <T extends A>; in this case it would be useful. How can I make a similar thing in C++ with templates?
I have modified the code this way:
#include <iostream>
#include <vector>
class A { };
class B : virtual public A { };
class C : virtual public A { };
class D : public C, public B { };
using namespace std;
template<class T>
void print_type(T* info)
{
if(dynamic_cast<D*>(info))
cout << "D" << endl;
else if(dynamic_cast<C*> (info))
cout << "C" << endl;
else if(dynamic_cast<B*>(info))
cout << "B" << endl;
else if(dynamic_cast<A*> (info))
cout << "A" << endl;
}
int main(int argc, char** argv)
{
string str;
print_type(&str);
return 0;
}
But I still get the error: 'std::basic_string<char>' is not polymorphic
First of all, this is not a templates problem. If you remove the template and just have print_type take a D*, you'll see that the error will still be there.
What is happening is you do not use virtual inheritance, hence you get this situation:
A A
| |
B C
\ /
D
The dynamic_cast doesn't know which A you are refering to.
To achieve this: (and I assume it's what you wanted)
A
/ \
B C
\ /
D
...you should use virtual inheritance, ergo:
class A
{
};
class B : virtual public A
{
};
class C : virtual public A
{
};
class D : public C,public B
{
};
... and now it compiles without problems :) (keep in mind that Virtual Inheritance Is Evil though)
This is called a deadly diamond of death, or simply, diamond problem. The "path" to A can go through either B or C, hence a potential contradiction.
Furthermore, the idea of a template is to make it generic, not type aware. A template is not in itself compiled code, it's compiled against its use. It's a lot like a big macro.
Consider the problem of getting an object as argument and printing it's type:
Sigh... use RTTI.
#include <iostream>
#include <string>
#include <typeinfo>
template<class T> void print_type(const T& info){
std::cout << typeid(info).name() << std::endl;
}
int main(int argc, char** argv){
D d;
int a = 3;
std::string test("test");
print_type(d);
print_type(a);
print_type(test);
return 0;
}
Related
I would like to create a C++ class with a default template parameter. However, I am having the following error:
error: invalid use of incomplete type
The code is the follow:
#include <iostream>
#include <string>
#include <array>
typedef std::array<double, 3> vec;
enum Op {Op1, Op2, Op3};
template<class T, enum Op S=Op1>
class classA
{
public:
class classInsideA
{
public:
classInsideA() {}
void tst()
{
std::cout << "inside A"<< std::endl;
}
};
void foo();
};
template<class T>
void classA<T>::foo() // not working
{
std::cout<< "I am being called in here" << std::endl;
}
int main(int argc, char** argv)
{
classA<vec> obj2;
return 0;
}
I would like that the default template would not change any of the current syntax in the class classA.
How can I fix this?
Edit:
Making the function have 2 template parameters, works.
template<class T, Op S>
void classA<T, S>::foo()
{
std::cout<< "I am being called in here" << std::endl;
}
But if the function has a default parameter, why do I need to specify the two templates. Shouldn't assume the default one?
Simply a typo I believe! You class has two template parameters and your function definition must also use both. See the full example below or here
typedef std::array<double, 3> vec;
enum Op {Op1=99, Op2, Op3};
template<class T, Op S=Op1>
class classA
{
public:
class classInsideA
{
public:
classInsideA() {}
void tst()
{
std::cout << "inside A we use Op value"<< S << std::endl;
}
};
classInsideA dummy;
void foo();
};
template<class T, Op S>
void classA<T, S>::foo() // not working
{
std::cout<< "I am being called in here and we use Op value" << S << std::endl;
}
int main(int argc, char** argv)
{
classA<vec> obj2;
obj2.dummy.tst();
obj2.foo();
return 0;
}
I made an empty class having specific offset and want to derived class using that area..
like below code.. I use alignas()
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
#pragma pack (push, 1)
class alignas(32) base
{
public:
base() { init(); }
void init() { memset(this, 0, 32); }
}; // sizeof(base) = 32
class derived01 : public base
{
int a;
int b;
}; // sizeof(derived01) = 32
class derived02 : public base
{
char a[20];
}; // sizeof(derived02) = 32
class item
{
int a;
base b;
int c;
public:
template <typename T>
inline T GetDerived()
{
return reinterpret_cast<T>(&b);
}
};
#pragma pack (pop)
int main()
{
cout << "ItemUnit :" << sizeof(base) << endl;
cout << "derived01 :" << sizeof(derived01) << endl;
cout << "derived02 :" << sizeof(derived02) << endl;
cout << "item :" << sizeof(item) << endl;
// I want to get Derived Class like this..
//item* i = new item();
//derived02 d = i.GetDerived<derived02>();
return 0;
}
and, it seemed to work as expected.. In LINUX.. (g++ 7.4)
# ./a
ItemUnit :32
derived01 :32
derived02 :32
item :40
but in MSVS2019, it returned..
ItemUnit :32
derived01 :32
derived02 :32
item :96
I also thought about other ways, but they have some....
UNION but, it cant using inheritance.. and I think it inconvenient to use.
make base class having char[32].. and derived having only functions to get,set using offset..
Is there any other good way?
please advice..
I want to pass a pointer to a class method and call that function from an iterator. The code below fails to compile when I include a derived object.
I've tried using a typename for the class specifier (e.g. TC::*pf) but this doesn't work. Can someone suggest how to make this work?
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
using std::endl;
using std::vector;
class Base {
public:
Base(int bval) : bval_(bval) { }
virtual void print() {
cout << "Base: bval:" << bval_ << endl;
}
protected:
int bval_;
};
class Derived : public Base {
Derived(int bval, int dval) : Base(bval), dval_(dval) { }
virtual void print() {
cout << "Derived: bval:" << bval_ << " dval:" << dval_ << endl;
}
private:
int dval_;
};
typedef vector<Base*> MyVecType;
typedef MyVecType::iterator MyVecTypeIter;
template <typename T>
void testFunc(MyVecType& v, T (Base::*pf)()) {
for (MyVecTypeIter iter = v.begin(); iter != v.end(); ++iter) {
((*iter)->*pf)();
}
}
int main() {
MyVecType bvec;
bvec.push_back(new Base(44));
bvec.push_back(new Base(55));
// above compiles and runs ok, but this fails to compile
// with 'no matching function' error:
bvec.push_back(new Derived(66));
testFunc(bvec, &Base::print);
return 0;
}
line
bvec.push_back(new Derived(66));
does not compiler because Derived class constructor is private and is defined to take two int arguments.
Fix that and it will compile and run:
http://cpp.sh/9nrkc
In this sample code, there is two sentences showing the same static variable. The first one gives no ambiguity, but the second one does, why?
#include <iostream>
using namespace std;
struct A { static const char a = 'a'; };
struct B : public A { };
struct C : public A { };
struct G : public B, public C { };
int main()
{
G v;
cout << G::B::A::a << endl;
cout << v.B::A::a << endl;
}
GCC error (according to some comments, there's no ambiguity in clang):
main.cpp:15:18: error: 'A' is an ambiguous base of 'G'
cout << v.B::A::a << endl;
Code on coliru
This is clearly a bug in GCC, as a GCC maintainer recommends you report it. However, until it's fixed, you can use a nasty workaround like this:
std::cout << static_cast<B &>(v).A::a;
The advantage is this will help disambiguate if in a (complex) scenario that there are variables with the same name in one of the base classes.
#include <iostream>
using namespace std;
class B
{
public:
int getMsg(int i)
{
return i + 1;
}
};
class A
{
B b;
public:
void run()
{
taunt(b.getMsg);
}
void taunt(int (*msg)(int))
{
cout << (*msg)(1) << endl;
}
};
int main()
{
A a;
a.run();
}
The above code has a class B inside a class A, and class A has a method taunt that takes a function as an argument. class B's getMsg is passed into taunt...The above code generated the following error message: "error: no matching function for call to 'A::taunt()'"
What's causing the error message in the above code? Am I missing something?
Update:
#include <iostream>
using namespace std;
class B
{
public:
int getMsg(int i)
{
return i + 1;
}
};
class A
{
B b;
public:
void run()
{
taunt(b.getMsg);
}
void taunt(int (B::*msg)(int))
{
cout << (*msg)(1) << endl;
}
};
int main()
{
A a;
a.run();
}
t.cpp: In member function 'void A::run()':
Line 19: error: no matching function for call to 'A::taunt()'
compilation terminated due to -Wfatal-errors.
I'm still getting the same error after changing (*msg)(int) to (B::*msg)(int)
b.getMsg is not the correct way to form a pointer to member, you need &B::getMsg.
(*msg)(1) is not the correct way to call a function through a pointer to member you need to specify an object to call the function on, e.g. (using a temporary) (B().*msg)(1).
The right way to do such things in OOP is to use interfaces so all you need to do is to define an interface and implement it in B class after that pass the pointer of instance which implements this interface to your method in class A.
class IB{
public:
virtual void doSomething()=0;
};
class B: public IB{
public:
virtual void doSomething(){...}
};
class A{
public:
void doSomethingWithB(IB* b){b->doSomething();}
};
This works in VS 2010. The output is the same on all lines:
#include <iostream>
#include <memory>
#include <functional>
using namespace std;
using namespace std::placeholders;
class A
{
public:
int foo(int a, float b)
{
return int(a*b);
}
};
int main(int argc, char* argv[])
{
A temp;
int x = 5;
float y = 3.5;
auto a = std::mem_fn(&A::foo);
cout << a(&temp, x, y) << endl;
auto b = std::bind(a, &temp, x, y);
cout << b() << endl;
auto c = std::bind(std::mem_fn(&A::foo), &temp, _1, y);
cout << c(5) << endl;
}
Basically, you use std::mem_fn to get your callable object for the member function, and then std::bind if you want to bind additional parameters, including the object pointer itself. I'm pretty sure there's a way to use std::ref to encapsulate a reference to the object too if you'd prefer that. I also included the _1 forwarding marker just for another way to specify some parameters in the bind, but not others. You could even specify everything BUT the class instance if you wanted the same parameters to everything but have it work on different objects. Up to you.
If you'd rather use boost::bind it recognizes member functions and you can just put it all on one line a bit to be a bit shorter: auto e = boost::bind(&A::foo, &temp, x, y) but obviously it's not much more to use completely std C++11 calls either.