Lets say I want to define an abstract class called A which has the virtual method get_range which should return a set of numbers. Sub classes of it will override the method get_range to return different numbers.
Here is my try:
#include <iostream>
#include <ranges>
#include <vector>
class A {
public:
virtual auto get_range() const -> std::ranges::view auto {
return std::views::all(data);
}
protected:
std::vector<int> data = {1, 2, 3, 4};
};
class B : public A {
public:
virtual auto get_range() const -> std::ranges::view auto override {
std::cout << "B::get_range().." << std::endl;
return data | std::views::transform([](int x) { return x * 2; });
}
};
class C : public A {
public:
virtual auto get_range() const -> std::ranges::view auto override {
std::cout << "C::get_range().." << std::endl;
return data | std::views::transform([](int x) { return x * 3; });
}
};
int main() {
A* a = new A();
A* b = new B();
A* c = new C();
for (auto x : a->get_range()) {
std::cout << x << " ";
}
std::cout << std::endl;
for (auto x : b->get_range()) {
std::cout << x << " ";
}
std::cout << std::endl;
for (auto x : c->get_range()) {
std::cout << x << " ";
}
std::cout << std::endl;
delete a;
delete b;
delete c;
return 0;
}
I expect numbers returned by B and C to be multiplications of original numbers in the vector multiplied by 2 and 3. But What it print is the original vector.
What am I doing wrong here?
Lets say I want to define an abstract class called A which has the virtual method get_range which should return a set of numbers. Sub classes of it will override the method get_range to return different numbers.
Here is my try:
#include <iostream>
#include <ranges>
#include <vector>
class A {
public:
virtual auto get_range() const -> std::ranges::view auto {
return std::views::all(data);
}
protected:
std::vector<int> data = {1, 2, 3, 4};
};
class B : public A {
public:
virtual auto get_range() const -> std::ranges::view auto override {
std::cout << "B::get_range().." << std::endl;
return data | std::views::transform([](int x) { return x * 2; });
}
};
class C : public A {
public:
virtual auto get_range() const -> std::ranges::view auto override {
std::cout << "C::get_range().." << std::endl;
return data | std::views::transform([](int x) { return x * 3; });
}
};
int main() {
A* a = new A();
A* b = new B();
A* c = new C();
for (auto x : a->get_range()) {
std::cout << x << " ";
}
std::cout << std::endl;
for (auto x : b->get_range()) {
std::cout << x << " ";
}
std::cout << std::endl;
for (auto x : c->get_range()) {
std::cout << x << " ";
}
std::cout << std::endl;
delete a;
delete b;
delete c;
return 0;
}
I expect numbers returned by B and C to be multiplications of original numbers in the vector multiplied by 2 and 3. But What it print is the original vector.
What am I doing wrong here?
Share Improve this question edited Feb 15 at 5:56 peter asked Feb 15 at 4:32 peterpeter 1179 bronze badges 11 | Show 6 more comments1 Answer
Reset to default 1Live code
The code compiles and runs with GCC 14.2, but the output is wrong. CLang 19.1 generates the error function with deduced return type cannot be virtual.
I'm going with CLang being correct.
The GCC output shows that C::get_range
is called with ca->get_range,
and the value inside the function is transformed. But the returned value is the original value from A.
Commenting the println
in get_range
doesn't change the returned value.
When called with cc,
the returned value is transformed, as expected.
#include <ranges>
#include <vector>
namespace rng = std::ranges;
namespace vws = std::views;
#include <fmt/ranges.h>
using fmt::println, fmt::print;
class A {
public:
virtual ~A() = default;
[[nodiscard]] virtual auto get_range() const -> std::ranges::view auto {
return std::views::all(data);
}
protected:
std::vector<int> data = {1, 2, 3, 4};
};
class C : public A {
public:
[[nodiscard]] auto get_range() const -> std::ranges::view auto override {
auto mod_data = data | std::views::transform([](int x) {
return x * 3;
});
println("gr {}", mod_data);
return mod_data;
}
};
auto main() -> int {
A* a = new A();
A* ca = new C();
C* cc = new C();
println("a {}\n", a->get_range());
println("ca {}\n", ca->get_range());
println("cc {}\n", cc->get_range());
delete a;
delete ca;
delete cc;
return 0;
}
GCC output.
[1, 2, 3, 4]
gr [3, 6, 9, 12] << C::get_range called !!!
ca [1, 2, 3, 4] << why?
gr [3, 6, 9, 12]
cc [3, 6, 9, 12]
evenseries.get_number() | views::transform(...)
? When you try to do it with a virtual function, the return type has to be the same type, with a minor exception that I don't think applies here. Do you want each class to return a different container type? – Rud48 Commented Feb 15 at 5:08any_view
, although the standard currently doesn't have one. – 康桓瑋 Commented Feb 15 at 7:51