C++ “为什么可以?”;模板<;T级>;无效f(T&T)“;覆盖T中的函数,但;模板<;T级>;无效f(T)“;不能
我有一个类a和子类B,想做一个模板函数来调用a和B的虚拟函数:C++ “为什么可以?”;模板<;T级>;无效f(T&T)“;覆盖T中的函数,但;模板<;T级>;无效f(T)“;不能,c++,function,templates,object-slicing,C++,Function,Templates,Object Slicing,我有一个类a和子类B,想做一个模板函数来调用a和B的虚拟函数: #include <stdio.h> class A{ public: virtual void test(){ printf("A\n"); } }; class B:public A{ public: virtual void test(){ printf("B\n"); } }; template<class T> void f(T t)
#include <stdio.h>
class A{
public:
virtual void test(){
printf("A\n");
}
};
class B:public A{
public:
virtual void test(){
printf("B\n");
}
};
template<class T>
void f(T t){
t.test();
}
int main(){
A* a=new B();
f<A>(*a);
return 0;
};
到
就像这样:
#include <stdio.h>
class A{
public:
virtual void test(){
printf("A\n");
}
};
class B:public A{
public:
virtual void test(){
printf("B\n");
}
};
template<class T>
void f(T& t){
t.test();
}
int main(){
A* a=new B();
f<A>(*a);
return 0;
};
#包括
甲级{
公众:
虚空试验(){
printf(“A\n”);
}
};
B类:公共A{
公众:
虚空试验(){
printf(“B\n”);
}
};
模板
空f(T&T){
t、 test();
}
int main(){
A*A=新的B();
f(*a);
返回0;
};
,它会打印B,为什么会发生这种情况?通过使用指针或引用来实现超驰。请务必阅读一篇关于多态性的好文章。 快乐编码。当您使用
template<class T>
void f(T t){ ... }
当你调用<代码> f(t t)< />代码时,C++实际上是构造函数T的一个对象:代码> t(t & t)< /COD>。然后将该对象的引用传递到函数中
你调用编写代码来证明它class A {
public:
int x;
A():x(6){
}
A(A& a) {
x = 2;
}
virtual void test() {
printf("%d\n", x);
}
};
class B : public A {
public:
virtual void test() {
printf("%d\n", x);
}
};
void fun(A a)
{
a.test();
}
void f(A& a)
{
a.test();
}
int main(void)
{
A* a = new A();
A* b = new B();
A* c = new A(*b);
fun(*a);
fun(*b);
f(*a);
f(*b);
f(*c);
}
输出是2 2 6 6 2如何定义类层次结构是类
B
从类A
派生而来。因此,当调用类B的
构造函数时,它必须先调用A的
构造函数,然后才能进行构造。A
和B
具有相同的虚拟函数或定义,称为test()
第一次实现f()
时,模板将在编译时推断参数类型。它寻找的是一种类类型,主要是当你调用模板函数时,你告诉这个模板函数期望一种类a
的类型。然后将使用A::test()
调用测试函数。在调用f()
之前,在main函数中动态创建类型为class a
的指针并将其放置在堆中,但使用的是B
的构造函数,它是a
的派生类型。这将使用B的
构造函数调用A的
构造函数。模板函数需要类型A
,因此它在代码中调用A.test()
或A::test()
在f()
的第二个声明或定义中,类的定义和行为完全相同。这次不同的是,您的模板函数将在编译期间解析,以推断其参数的类型。在这个版本的函数中,它需要类类型A
的地址,因为现在它需要的是内存地址,而不是实际变量本身,这一次是在实例化或调用函数f()时<代码>期望类型为<代码> t>和代码>的参数,它现在使用C++的引用能力,现在调用<代码> b测试()(代码)>p>
如果您想了解发生这种情况的原因,请使用f()
的第一个声明,并在a*a=new B()处设置一个断点代码>并逐行进入代码,不要跨过去,而是进入。然后对第二个版本的f()
执行相同的过程,您将看到发生了什么
这不是因为类正在重写或没有重写虚函数;这是由于模板函数是如何工作的
现在我的问题是,为什么要为基类型创建指针,并通过调用其派生类型的构造函数为其设置新内存
通常,对于多态性和抽象类,您通常会创建一种派生类,但您可能有一个容器,其中包含指向派生类基类的指针,您通常会在该基类中动态强制转换它们。例如,假设您有一个抽象的Automobile
基类;这意味着您不能直接创建这个类,因为它的构造函数受到保护,只有派生类型才能访问它。现在,派生类型可能是汽车
,货车
,卡车
,SUV
,吉普
,摩托车
,在某些其他类别或功能中,可能存储了向量
。因此,通过这种方式,您可以将卡车、汽车和面包车的智能指针推送到同一个容器中,方法是动态地将这些构造的对象指针转换到它们的基本类型Automobile
,因为它们都是从它们公开继承的!但是,在使用抽象类型时,需要特别小心
查看这个小程序,看看多态性是如何工作的(这里没有抽象类型)
对于f()
模板函数的第一个版本,使用dynamic\u cast
,对于g()使用static\u cast
,这可能有助于您了解两种不同模板类型的情况
用于模板函数的第二个版本,该函数采用引用而不是变量的堆栈副本
如果您还记得,此向量中有两个元素,第一个是DerivedA*
,第二个是DerivedB*
,它们都属于Base
类型,并作为Base*
存储在向量中。输出的前4行是仅对向量的第一个元素所做的功!输出的最后4行是仅对向量的第二个元素所做的功
我们在索引0
处存储的第一个元素属于DerivedA
类型,存储为Base*
并且第一次调用f()
我们动态地将其转换为DerivedA*
类型,然后取消引用指针。第二次调用f()
我们做了同样的事情,只是我们动态地将它强制转换为DerivedB*
类型并遵从它。因此,这里第一个存储的对象调用DerivedA::test()
,然后使用动态转换调用DerivedB::test()
接下来的两行仍然在同一个元素上工作,这是我们的
template<class T>
void f(T t){ ... }
template<class T>
void f(T& t){ ... }
class A {
public:
int x;
A():x(6){
}
A(A& a) {
x = 2;
}
virtual void test() {
printf("%d\n", x);
}
};
class B : public A {
public:
virtual void test() {
printf("%d\n", x);
}
};
void fun(A a)
{
a.test();
}
void f(A& a)
{
a.test();
}
int main(void)
{
A* a = new A();
A* b = new B();
A* c = new A(*b);
fun(*a);
fun(*b);
f(*a);
f(*b);
f(*c);
}
#include <conio.h>
#include <string>
#include <iostream>
#include <vector>
#include <memory>
class Base {
public:
Base() {}
virtual ~Base(){}
virtual void test() const { std::cout << "Base" << std::endl; }
};
class DerivedA : public Base {
public:
DerivedA() : Base() {}
virtual ~DerivedA() {}
virtual void test() const override { std::cout << "DerivedA" << std::endl; }
};
class DerivedB : public Base {
public:
DerivedB() : Base() {}
virtual ~DerivedB() {}
virtual void test() const override { std::cout << "DerivedB" << std::endl; }
};
template<class T>
void f( T t ) {
t.test();
}
template<class T>
void g( T& t ) {
t.test();
}
int main() {
DerivedA* a = new DerivedA();
//f<DerivedA>( *a );
//g<DerivedA>( *a );
DerivedB* b = new DerivedB();
//f<DerivedB>( *b );
//g<DerivedB>( *b );
std::vector<Base*> vBases;
vBases.push_back( a );
vBases.push_back( b );
for ( unsigned i = 0; i < vBases.size(); ++i ) {
if ( i == 0 ) {
std::cout << "First Iteration: i = " << i << std::endl;
} else if ( i == 1 ) {
std::cout << "Second Iteration: i = " << i << std::endl;
}
f<DerivedA>( *dynamic_cast<DerivedA*>( vBases[i] ) );
f<DerivedB>( *dynamic_cast<DerivedB*>( vBases[i] ) );
std::cout << std::endl;
g<DerivedA>( *static_cast<DerivedA*>( vBases[i] ) );
g<DerivedB>( *static_cast<DerivedB*>( vBases[i] ) );
std::cout << std::endl;
}
delete a; // You Forgot To Delete Your Dynamic Pointers - Memory Leak!
delete b;
std::cout << "Press any key to quit" << std::endl;
_getch();
return 0;
}
DerivedA
DerivedB
DerivedA
DerivedA
DerivedA
DerivedB
DerivedB
DerivedB