我一直在互联网上搜索这个话题,我还没有真正得到一个坚定的答案。作为一个C#程序员,我习惯于在大范围内声明类,通常在文件顶部附近,在任何函数之外,然后在使用时构造它们。
继续使用C ++之后,复制它的唯一方法是使用默认构造函数,这很好,但在某些情况下,我宁愿使用一个构造函数,它需要参数而不是一个无参数的默认构造函数。 / p>
在互联网上寻找解决方案后,我发现了一些有缺陷的建议:
1。指针
有些人建议在所需的范围内使用动态指针,然后在构造时将指针指向指向类的位置。
CClass* pClass = 0;
int main()
{
pClass = new CClass(1337);
delete pClass;
return 0;
}
这种方法的问题在于你必须记住之后删除指针,因此,静态指针更加“安全”。此外,我猜测由于有指针,这会有轻微的内存开销,虽然不多,但
2。无论如何都有默认构造
有时建议使用默认构造函数,它只是将类中的所有内容归零:
class CClass
{
public:
CClass() : leetNumber(0) {}
CClass(int leetNumber) : leetNumber(leetNumber) {}
private:
int leetNumber;
};
//Defaults leetNumber to 0 through default ctor
CClass myClass;
int main()
{
myClass = CClass(1337);
return 0;
}
但是,如果你不能把课堂内的所有内容归零,会发生什么?如果你有另一个课程,不能只是初始化为什么怎么办?如果用户在没有正确初始化成员的情况下尝试访问类中的函数,您会怎么做? (你可以检查一下,但我相信它需要太多的代码,特别是如果你有很多成员的话)。
第3。保持更小,更本地化的范围
有人建议人们说要留在一个小范围内,把这个类作为对可能需要它的其他函数的引用传递,并在他们宣布该类时立即构建:
class CClass
{
public:
CClass(int leetNumber) : leetNumber(leetNumber) {}
int getLeetNumber() { return leetNumber; }
private:
int leetNumber;
};
bool GetMuchNeededAmazingNumberFromClass(CClass& myClass)
{
if(myClass.getLeetNumber() == 1337)
return true;
return false;
}
int main()
{
CClass myClass = CClass(1337);
if(!GetMuchNeededAmazingNumberFromClass(&myClass);
return 1;
return 0;
}
这是好的,你可以看到什么函数需要什么,但我可以想象一个函数需要很多具有大量所需参数的外部类。
还有更多的例子,但我似乎无法找到一个我可以依赖的例子,特别是来自C#背景,这里的东西很简单。
感谢。
修改
让我详细说明我要求的内容 - 在C#中,您可以执行以下操作:
public class Program
{
//See how I'm able to do this, without calling the ctor.
static AmazingClass amazing;
public static void Main()
{
//And then call the constructor when I want.
amazing = new AmazingClass(1337);
}
}
这允许我创建类而不实际构建它,这是我在C ++中寻找的。 p>
再次感谢。
答案 0 :(得分:6)
这是一个非常糟糕的习惯(用对象替换了类):
我习惯于在大型中声明对象 范围,通常靠近文件的顶部,在任何函数之外,和 然后在使用时构建它们。
忘了它。在需要时定义对象。
int main() {
A a;
...a...
A b;
...b...
}
这是C ++的思考。
我相信C#也是坏习惯。如果您在没有定义对象的情况下使用对象会怎么样 - 您将获得空引用异常 - 为什么要玩这样危险的东西。
BTW,相当于C#对象的C ++是shared_ptr:std::shared_ptr<A> a;
int main() {
a = std::make_shared<A>(...);
// do not need to call delete
}
在C ++中,如果您不需要共享对象,也可以使用std::unique_ptr
。
但是不要这样做,不要使用全局变量......
答案 1 :(得分:4)
这是因为在C#中,类是基于堆的引用对象。所以:
C#
MyClass a; //null reference
a = new MyClass (param1, param2);
然而:
C ++
MyClass a; //Myclass is constructed on stack
C#版本与C ++相同:
Myclass* a = 0; //null reference
a = new Myclass (param1, param2);
一个类可以在C ++中存在于堆栈中,而它不能在C#中存在。
C#提供了一个可以存在于堆栈中的结构值类型:
MyStruct a; //lives on the stack
但是我可以提供带有参数的结构构造函数:
struct MyStruct
{
public MyStruct (int a, int b) { /*assign to members vars*/ }
int A, B;
}
C#代码:
MyStruct a; // this creates a on stack and zero initializes int A and B
此:
MyStruct a; //does same as above
a = new Mystruct(1, 2); //a.A = 1, a.B = 2
答案 2 :(得分:2)
- 保持更小,更本地化的范围
醇>
这是你应该做的,不仅在C ++中,而且在所有语言中都是如此。
但是我可以想象一个函数需要很多具有大量所需参数的外部类。
函数应该采用他们需要的参数。如果你觉得有太多,也许你应该将功能重构为其他部分。参数的数量只是衡量函数复杂性的另一个指标。访问全局对象不仅不会简化功能,而且会使识别全局对象的使用/访问/修改位置变得更加困难,从而使代码的维护变得更加复杂。
如果你的函数需要很多参数,要么它不是真正的函数,而是不同操作的复杂混乱,否则参数可能分组在一些有意义的实体中。在后一种情况下,只需创建表示这些实体的类型,您最终将传递一些参数。
另一方面,我不确定在C#中你真的做了你说你正在做的事情......特别是,C#中的大多数代码都是在类中,所以你习惯做的很可能就是上课成员在顶部声明并在其他地方使用。如果是这种情况,您可以在C ++中应用相同的范例。创建类,包含您需要的成员数。
答案 3 :(得分:1)
听起来你想要重载构造函数。
答案 4 :(得分:1)
在函数中使用静态变量来延迟对象的创建,直到需要为止。
Foo & getInstance () {
static Foo foo(arg1, arg2, ...);
return foo;
}
void main () {
Foo & x = getInstance();
}
如果您需要getInstance
来创建动态对象(如getInstance(x, y, z)
中所述),但只想传递一次aguments,则可以执行以下操作:
struct FooFactory {
int arg1;
float arg2;
Bar arg3;
bool valid;
FooFactory ();
Foo & getInstance ();
};
FooFactory::FooFactory () : valid(false) {}
Foo & FooFactory::getInstance () {
if (!valid) throw Error();
static Foo foo(arg1, arg2, arg3);
return foo;
}
FooFactor factory;
void main () {
factory.arg1 = ...;
factory.arg2 = ...;
factory.arg3 = ...;
factory.valid = true;
Foo & x = factory.getInstance();
}
当然这是基础知识。我不打扰信息隐藏或类似的东西。您可以使用factory.getInstance()
代替operator() ()
并将getInstance ()
重命名为factory
来避免getInstance
。我也不是说这个好主意。我只是在展示如何完成OP的问题。
答案 5 :(得分:1)
//See how I'm able to do this, without calling the ctor.
static AmazingClass amazing;
//And then call the constructor when I want.
amazing = new AmazingClass(1337);
所有内容(好吧,几乎所有内容)都是C#中的引用。在您通过amazing
分配变量之前,该变量new
不会引用任何内容。这是C ++的等价物:
//See how I'm able to do this, without calling the ctor.
static AmazingClass * amazing;
//And then call the constructor when I want.
amazing = new AmazingClass(1337);
因为(几乎)所有东西都是C#和Java中的引用,你必须new
这个,new
,new
这些语言中的所有内容。您可以通过使所有内容成为指针来在C ++中获得相同的行为,但这样做并不是首选机制。 C ++没有自动垃圾收集。您在C ++中通过new
分配的所有内容最终都必须通过delete
删除。 C ++中的首选机制是将new
和delete
降至最低。
解决C ++中new
/ delete
问题的一种方法是绕过new
。只需声明所需类型的变量即可。这给了你在Java和C#中无法做到的事情。您可以声明类型的变量,但Java和C#不允许您查看对象本身。这些语言中的对象总是隐藏在引用之后。
C ++中new
/ delete
问题的另一种解决方法是使用RAII。 new
和delete
命令隐藏在类方法中,析构函数总是在自身之后清理。班上做了肮脏的工作。对外界你只需要上课。
C#和C ++是不同的语言。你必须采用不同的思维方式才能正确使用这两种语言。