- 说明:**
我试图根据用户输入创建一个类对象。我试图用指针存储它的引用,并在稍后阶段使用它。与Dart语言中的变量类型late
类似的想法。是否可以在CPP中进行此操作?如果可以,我应该使用哪种类型的变量?
- 代码:**
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class foo {
public:
T item;
foo(){}
};
class bar_1 {
public:
int value = 99;
void randomise();
};
class bar_2{
public:
string value = "init";
void randomise();
};
int main()
{
int i;
cin >> i;
void* ptr;
if (i > 0) {
ptr = new foo<bar_1>;
}
else {
ptr = new foo<bar_2>;
}
// maybe run the function to randomise 'value'
// ptr->item.randomise();
cout << ptr->item.value;
return 0;
}
- 错误:**
cout << ptr->item.value;
| ^~
error: ‘void*’ is not a pointer-to-object type
- 编辑1:**我不允许修改类栏atm,aschepler的#1解决方案最适合。
- 编辑2:**我正在重新考虑这个问题。我发现最直接的方法是使用一个模板转储并将它们转换成一个类层次结构,其中'bar 1'和'bar 2'是'foo'的后代类。因此,如果指向类'foo'的指针存在于作用域中,它可以被赋值为指向'bar 1'或'bar 2'对象的指针。
- 更新代码:(类层次结构)**
#include <iostream>
using namespace std;
class foo {
public:
// common function going to be overrided by children classes
virtual void randomize() {
}
};
class bar_1: public foo {
public:
int value = 99;
// bar_1 version of randomize()
void randomize() override {
cout << "Turning int from " << value << " to a new int\n";
value++; // increment by 1
}
};
class bar_2: public foo {
public:
std::string value = "something";
// bar_2 version of randomize()
void randomize() override {
cout << "Turning string from " << value << " to a new string\n";
value = "new thing"; // diff string
}
};
int main()
{
int type = 1; // e.g type can variate from 1 to 10
foo* ptr;
switch(type)
{
case 1:
ptr = new bar_1();
break;
case 2:
ptr = new bar_2();
break;
// case 3:
// ...
default:
cout << "Invalid type\n";
break;
}
ptr->randomize();
return 0;
}
- 更新代码:(继续使用模板类)**
#include <iostream>
#include <variant>
#include <optional>
using namespace std;
template <typename T>
class foo {
public:
T item; // an object either bar_1 or bar_2
foo(T _item) : item(_item) {} // constructor assigning in-class variable "item"
T getItem() // template function returning the in-class variable item
{
return item;
}
};
class bar_1 {
public:
int value = 99;
};
class bar_2{
public:
string value = "str";
};
int main()
{
int i = 0; // some value
optional<variant<foo<bar_1>, foo<bar_2>>> foo_foo;
if (i > 0) {
foo_foo = foo(bar_1());
}
if (i < 0) {
foo_foo = foo(bar_2());
}
// using visit
// if i > 0, it gives 99 as foo.item has type bar_1, which has an int value 99
// if i < 0, it gives "str" as foo.item has type bar_2, which has an string value "str"
// if i == 0, it gives 0 as the optioanl variable foo_foo contains no values
visit([](auto &_foo) { cout << _foo.getItem().value; }, *foo_foo);
return 0;
}
2条答案
按热度按时间wqnecbli1#
当然不是像JS和(AFAIK)Dart这样的动态语言所允许的方式。
C++是静态类型的,所以当你在一个(非模板的)函数中写
cout << ptr->item.value
时,必须知道item
和value
的类型,不能在运行时混淆不相关的类型,比如int
和string
。然而,你也可以使用继承来达到你想要的效果。一个对象的指针总是可以被转换成指向它的(可访问的,例如
public
)基的指针,并且像基一样被访问--但是对象将保留它的实际类型,并且base
的所有 virtual 方法将作用于该类型,并且可以被覆盖:或使用智能指针(强烈推荐):
5sxhfpxr2#
正如注解所指出的,不能在块结束后使用指向块中声明的变量的指针,可以使用
std::unique_ptr
或std::optional
来解决这个问题。这里有两种可能的解决方案。
1:
std::variant<foo<bar_1>, foo<bar_2>>
可以包含任何一种类型的对象,而不需要对现有的类做任何修改(也不需要任何动态分配),然后我们可以使用std::visit
来处理它所包含的任何对象。2如果你可以改变类,注意
bar_1
和bar_2
都包含一些公共操作“randomise item”和“print item”。所以我们可以创建一个接口,允许多态使用这些操作,而不需要知道实际类型。如果你以后添加其他类似的类,这也更容易扩展。现在
foo
甚至不需要是一个模板,它只需要使用一个接口指针来代替实际类型的成员: