C++ - 希望虚拟仅作为重定向

发布于 2024-09-30 05:09:06 字数 1152 浏览 2 评论 0原文

假设我有一个模板:

template <class N, class I>
void add(N* element, std::list<N*> & container, I (N::*f)() const,
        std::string successmsg, std::string exceptmsg) {
//...
}

我想调用它来获取指向派生类的基类指针的列表。

add(newAirplane, airplanes, &Airplane::getRegistration,
        "Added!", "Error: Existent!");

Airplane 继承自AirplaneType

当然,它无法编译,N 首先定义为 AirplaneType,然后定义为 Airplane

我添加了一个虚拟 getRegistration @AirplaneType 但当然,编译器会给出 vtable 错误。

解决这个问题的正确方法是什么? AirplaneType 没有 registration 属性,我对它拥有一个不感兴趣。我还想避免 virtual getRegistration() const {return "";}

有什么好的实践建议吗?

编辑:

感谢您的回答,但仍然不起作用。我想我已经找到了剩下的问题,但没有找到它的解决方案:

void Airline::addAirplane(AirplaneType* airplane) {
add(newAirplane, airplanes, &Airplane::getRegistration,
        "Added!", "Error: Existent!");

}

收到的指针类型是AirplaneType,而不是Airplane

airplanesAirplaneType 指针的列表。

Let's say I have a template:

template <class N, class I>
void add(N* element, std::list<N*> & container, I (N::*f)() const,
        std::string successmsg, std::string exceptmsg) {
//...
}

And I want to call it for a list of Base Class pointers to a derivative class.

add(newAirplane, airplanes, &Airplane::getRegistration,
        "Added!", "Error: Existent!");

Airplane inherits from AirplaneType.

Of course, it doesn't compile, N is first defined as AirplaneType and then as Airplane.

I added a virtual getRegistration @ AirplaneType but of course, the compiler gives out a vtable error.

What's the proper way to solve this? AirplaneType has no registration attribute and I'm not interested in it having one. I also wanted to avoid virtual getRegistration() const {return "";}

Any suggestions for good practice?

EDIT:

Thanks for answers, but still not working. I think I have found the remaining problem, but not its solution:

void Airline::addAirplane(AirplaneType* airplane) {
add(newAirplane, airplanes, &Airplane::getRegistration,
        "Added!", "Error: Existent!");

}

The type of pointer received is AirplaneType, not Airplane.

airplanes is a list of AirplaneType pointers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

随心而道 2024-10-07 05:09:10

由于 C++ 不处理逆变类型,因此您需要为公共基础添加额外的模板参数。也就是说,std::list 是与 std::list 完全不同的类型,并且不能从指向派生最多的指针到派生最少的指针列表。因此,实际上您的 add 函数需要变为:

template <class N, class I, class B>
void add(N* element, std::list<B*> & container, I (N::*f)() const,
        std::string successmsg, std::string exceptmsg)

You need to add an additional template parameter for the common base since C++ does not handle contravariant types. That is, std::list<Airplane*> is an entirely different type from std::list<AirplaneType*>, and no implicit conversion can occur from the list of pointers to the most derived to the least derived.. So, effectively your add function would need to become:

template <class N, class I, class B>
void add(N* element, std::list<B*> & container, I (N::*f)() const,
        std::string successmsg, std::string exceptmsg)
夏雨凉 2024-10-07 05:09:08

您需要另一个模板参数,因为您关心两个不同的类 - 指针的类型(以及您要使用它调用的成员函数)和容器的类型:

#include <list>

struct AirplaneType {
};

struct Airplane : AirplaneType {
    int check() const { return 3; }
};

template <typename T, typename U, typename I>
void add(T* element, std::list<U*> & container, I (T::*f)() const) {
    container.push_back(element);
    I i = (element->*f)();
}

int main() {
    std::list<AirplaneType*> ls;
    Airplane a;
    add(&a, ls, &Airplane::check);
}

在本例中,我的 add 函数并没有真正使用 container 是一个 list 的事实,因此更明智的版本可能是:

template <typename T, typename U, typename I>
void add(T* element, U & container, I (T::*f)() const) {
    container.push_back(element);
    I i = (element->*f)();
}

然后,您可以进一步抽象:

template <typename T, typename U, typename AUF>
void add(T element, U & container, AUF func) {
    container.push_back(element);
    typename AUF::result_type i = func(element);
}

。 ..但这对于调用者来说稍微不太方便:

#include <functional>

add(&a, ls, std::mem_fun(&Airplane::check));

有什么好的实践建议吗?

不要创建原始指针的容器。

编辑:要使其与虚拟函数一起使用,我的每个选项:

#include <list>
#include <functional>
#include <iostream>

struct AirplaneType {
    virtual int check() const { return 0; }
};

struct Airplane : AirplaneType {
    int check() const { std::cout << "check\n"; return 3; }
};

template <typename T, typename U, typename I>
void add(U* element, std::list<T*> & container, I (U::*f)() const) {
    container.push_back(element);
    I i = (element->*f)();
}

template <typename T, typename U, typename AUF>
void add2(T element, U & container, AUF func) {
    container.push_back(element);
    typename AUF::result_type i = func(element);
}

int main() {
    std::list<AirplaneType*> ls;
    Airplane a;
    add(static_cast<AirplaneType*>(&a), ls, &AirplaneType::check);
    add2(&a, ls, std::mem_fun(&AirplaneType::check));
}

输出是:

check
check

即使函数指针指向 AirplaneType::check,而不是 <,也显示覆盖被正确调用。代码>飞机::检查。

You need another template parameter, because you care about two different classes - the type of the pointer (and hence the member function you're going to call with it), and the type of the container:

#include <list>

struct AirplaneType {
};

struct Airplane : AirplaneType {
    int check() const { return 3; }
};

template <typename T, typename U, typename I>
void add(T* element, std::list<U*> & container, I (T::*f)() const) {
    container.push_back(element);
    I i = (element->*f)();
}

int main() {
    std::list<AirplaneType*> ls;
    Airplane a;
    add(&a, ls, &Airplane::check);
}

In this case my add function doesn't really use the fact that container is a list, so a more sensible version might be:

template <typename T, typename U, typename I>
void add(T* element, U & container, I (T::*f)() const) {
    container.push_back(element);
    I i = (element->*f)();
}

And then again, you could abstract further:

template <typename T, typename U, typename AUF>
void add(T element, U & container, AUF func) {
    container.push_back(element);
    typename AUF::result_type i = func(element);
}

... but that's slightly less convenient for the caller:

#include <functional>

add(&a, ls, std::mem_fun(&Airplane::check));

Any suggestions for good practice?

Don't create containers of raw pointers.

Edit: to get this working with a virtual function, with each of my options:

#include <list>
#include <functional>
#include <iostream>

struct AirplaneType {
    virtual int check() const { return 0; }
};

struct Airplane : AirplaneType {
    int check() const { std::cout << "check\n"; return 3; }
};

template <typename T, typename U, typename I>
void add(U* element, std::list<T*> & container, I (U::*f)() const) {
    container.push_back(element);
    I i = (element->*f)();
}

template <typename T, typename U, typename AUF>
void add2(T element, U & container, AUF func) {
    container.push_back(element);
    typename AUF::result_type i = func(element);
}

int main() {
    std::list<AirplaneType*> ls;
    Airplane a;
    add(static_cast<AirplaneType*>(&a), ls, &AirplaneType::check);
    add2(&a, ls, std::mem_fun(&AirplaneType::check));
}

Output is:

check
check

which shows that the override is correctly called even though the function pointer was taken to AirplaneType::check, not Airplane::check.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文