Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ “为什么可以?”;模板<;T级>;无效f(T&T)“;覆盖T中的函数,但;模板<;T级>;无效f(T)“;不能_C++_Function_Templates_Object Slicing - Fatal编程技术网

C++ “为什么可以?”;模板<;T级>;无效f(T&T)“;覆盖T中的函数,但;模板<;T级>;无效f(T)“;不能

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)

我有一个类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){
    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