C++代码不打印信息,怎么了?

C++代码不打印信息,怎么了?,c++,C++,我的示例代码有问题 任务是创建一个至少有一个动态成员的类,创建一些对象,打印一些内容,最后销毁它们。我已经编写了我的代码,它编译时没有任何错误或警告,但它不打印任何内容我使用的是VS2017社区版的Microsoft CL编译器 谁能给我一个提示,我做错了什么 动态h: 包括 包括 ifndef uuuuuuu类动态__ 定义类__ 类dyn{ 私有:std::字符串名称; 私人:国际*年龄; public:dynstd::string,int; 公众:戴恩康斯特戴恩&; 公众:~dyn; pu

我的示例代码有问题

任务是创建一个至少有一个动态成员的类,创建一些对象,打印一些内容,最后销毁它们。我已经编写了我的代码,它编译时没有任何错误或警告,但它不打印任何内容我使用的是VS2017社区版的Microsoft CL编译器

谁能给我一个提示,我做错了什么

动态h:

包括 包括 ifndef uuuuuuu类动态__ 定义类__ 类dyn{ 私有:std::字符串名称; 私人:国际*年龄; public:dynstd::string,int; 公众:戴恩康斯特戴恩&; 公众:~dyn; public:std::string-toString; }; 恩迪夫 dyn.cpp

包括dyn.h dyn::dynstd::字符串名称,整数年龄{ 此->名称=名称; *这个->年龄=年龄; } dyn::dynconst dyn&a{ 此->名称=a.名称; *这->年龄=*a.Age; } 戴恩::~戴恩{ 删除此->年龄; } std::string dyn::toString{ std::string tmp=人名+此->姓名; 返回tmp; } main.cpp

包括 包括dyn.h int main{ dyn*Person1=新的dyn{Mike,38}; dyn*Person2=新的dyn{Thomas,20}; dyn*Person3=Person1; std::cout toStringThx.@HolyBlackCat:

我改变了主意:

dyn::dynstd::字符串名称,整数年龄{ 此->名称=名称; 此->年龄=新摄入量; } 及

dyn::dynconst dyn&a{ 此->名称=a.名称; 这个->年龄=新的整数{*a.Age}; }
现在它按预期工作:

它位于分配给Age的两行中。在这些情况下,由于Age被声明为int*,*this->Age不是this->Age本身,而是this->Age指向的内存地址处的值。此外,由于这两行都在构造函数中,this->Age还没有有效地址,因此尝试ssign一个值将导致未定义的行为

正确的做法是在分配内存之前,按如下方式分配内存,以确保此->Age具有有效地址:

dyn::dyn(std::string Name, int Age){
    this->Name = Name;
    this->Age = new int();
    *this->Age = Age;
}

dyn::dyn(const dyn& a){
    this->Name = a.Name;
    this->Age = new int();
    *this->Age = *a.Age;
}
幸运的是,您已经在析构函数中删除了Age,因此不需要修改

但是我想学c++

所以当你已经有了一个适当的方法来解决这个问题的时候,我可能会给你一些额外的提示

首先,您已经发现,可以将参数传递给指针的构造函数本身:

this->Age = new int(Age);
this->Age = new int{*a.Age};

单独:调用构造函数的方法有两种,一种是括号,另一种是通过括号进行新的、统一的初始化,而后者表现出一些好的意图,我个人认为它是坏的,在我自己的代码最喜欢的例子中不使用它:STD::vector { 1, 2, 3 }调用,STD::向量{ 7 }。调用经典构造函数,创建包含七个元素的向量;比较:std::vector7和std::vector{7},后者显式地调用std::initializer_list构造函数。好吧,您可能想深入研究一下这个主题,然后自己决定是跟随我还是支持UI,但无论您选择什么,都应该始终如一地使用它,而不是在两者之间切换

然后习惯使用构造函数初始化器列表,不要与std::initializer\u list混淆

好的,甚至可以使用相同的标识符位置来明确哪一个是哪一个,但您可能更喜欢使用不同的标识符。对于复杂类型,本机类型int、double、pointers……没有太大区别,不过,问题有所不同:

dyn::dyn(std::string Name, int Age)
    // default constructor for Name is  s t i l l  called!
{
    this->Name = Name; // and now you do the assignment!
}
默认构造和赋值的成本可能或多或少,在任何情况下,直接初始化(如前所示使用初始化器列表所发生的)都更有效。此外,引用和非默认可构造类型只能通过这种方式初始化

然后参数类型:C如果参数是按值传递或引用,则由类型决定;在C++中,可以通过引用或值或第三选项通过指针传递任何类型,但需要明确表示!

dyn::dyn(std::string   Name, int Age) // by value (i. e. you make a  c o p y  of!)
dyn::dyn(std::string&  Name, int Age) // by reference
dyn::dyn(std::string*  Name, int Age) // by pointer
dyn::dyn(std::string&& Name, int Age) // for completeness: r-value reference
最后一个是一个允许移动语义的新概念,即将内容从一个对象移动到另一个对象。已经有了一个很好的方法,所以我将不再进一步讨论

但是,通过接受引用,您可以避免一个不必要的副本,并且由于您不打算更改参数,因此它应该是常量:

然后查看一下。确实,您得到了C++定义的默认赋值操作符,但它将简单地执行以下操作:

dyn::operator=(dyn const& other)
{
    Name = other.Name;
    Age = other.Age;    // now both objects will point to the same address
                        // and you'll get a double deletion error!
}
好的,也定义了移动分配,但这不会改变指针的任何内容。有了移动语义,Ro3扩展到了;虽然前者仍然是强制性的,但后者不是,但如果不遵循它,您将失去一个很好的优化可能性

现代C++处理动态分配内存的方法是使用智能指针,有后者,远不及常用的。

class dyn
{
private:
    std::unique_ptr<int> Age;
public:
    dyn(int Age) : Age(std::make_unique<int>(Age)) { }
};
最后一点是关于命名约定的最后一点。通常,类标识符有一个前导大写字母,其中变量成员、全局变量和局部变量都以一个小字母开头
信函数标识符是模棱两可的,有一些人喜欢大写字母,这是一种主要来自微软的约定,还有一些人更喜欢最初的小写字母,这是一种更古老的约定,也是更常见的约定。对于函数,您应该选择其中一个,但在任何情况下,都要始终如一地遵循它。

*此->年龄=年龄;在这里,年龄并没有指向任何东西,但你却试图去引用它。使用此->年龄=新年龄;。复制构造函数也是如此。您还忘了编写复制分配运算符。还请注意,您必须删除删除人员1;或删除人3;因为它们指向同一个对象。还有,在每个成员面前写公开:或私人:有什么意义呢?谢谢,这样做很有效。公私的事情:我通常在C编码,但要学习C++。你完全正确,C++中不需要,但是在C中我这样学习了,需要一些时间来适应我自己;这并没有解决这个问题,但包含两个连续下划线的名称(CLASS_DYN_uu)和以下划线开头,后跟大写字母的名称保留供实现使用。不要在代码中定义这样的名称。
dyn::operator=(dyn const& other)
{
    Name = other.Name;
    Age = other.Age;    // now both objects will point to the same address
                        // and you'll get a double deletion error!
}
class dyn
{
private:
    std::unique_ptr<int> Age;
public:
    dyn(int Age) : Age(std::make_unique<int>(Age)) { }
};
decltype(auto) f() { int n; return (n); } // returns a reference to n!