我目前正在学习C ++,来自C#/ Java背景,使用Visual Studio 2017。
我有一个关于在堆上创建对象并在路上正确引用它们的问题。到目前为止,我遇到了多个教程和做事方式。有些人建议尽可能使用智能指针,其他人则发誓the devils tool。
我目前的主要内容如下:
//Main
Person *makePerson()
{
string name;
int age;
cout << "Input name: ";
cin >> name;
cout << "Input age: ";
cin >> age;
return new Person(name, age);
}
Child *makeChild(Person &parent)
{
return new Child(*makePerson(), &parent);;
}
int main()
{
cout << "---Input parent data---" << endl;
Person *person = makePerson();
cout << "printing: " << *person << endl;
cout << "---Input child data---" << endl;
Child *child = makeChild(*person);
cout << "printing: " << *child << endl;
cout << "---end of main---" << endl;
delete person;
delete child;
return 0;
}
函数处理个人数据的输入并返回指向新Person对象的指针。然后我有一个函数,通过获取父引用并询问makePerson剩余数据来处理子对象的创建。
这可以被视为优秀的C ++吗?我怎样才能让它变得更好?我非常感谢一些代码示例。
正如一些人已经建议的那样,我可以用shared_ptr<Person> person
(重)或unique_ptr<Person>
(比共享更好)替换原始指针。
这是Person和子类的代码。请注意,Child具有类型为Person *parent
的原始指针。
//header
class Person
{
protected:
std::string name;
int age;
public:
Person();
Person(const Person& other);
Person(std::string inName, int inAge);
~Person();
virtual void print() const;
std::string getName() const;
int getAge() const;
Person &operator=(const Person &other);
//overload print functionality, act as if it was toString
friend std::ostream &operator<<(std::ostream &out, const Person &p);
};
//cpp
Person::Person() : name(""), age(0) {
std::cout << "Person empty constructor" << std::endl;
}
Person::Person(std::string inName, int inAge) : name(inName), age(inAge) {
std::cout << "Person (" << name << ") default constructor" << std::endl;
}
Person::Person(const Person & other) : name(other.name), age(other.age) {
std::cout << "Person (" << name << ") copy constructor" << std::endl;
}
Person::~Person() {
std::cout << "Person (" << name << ") destructor" << std::endl;
}
void Person::print() const {
std::cout << name << ", " << age << std::endl;
}
std::string Person::getName() const
{
return name;
}
int Person::getAge() const
{
return age;
}
Person & Person::operator=(const Person & other) {
std::cout << "Person (" << other.name << ") assignment constructor" << std::endl;
name = other.name;
age = other.age;
return *this;
}
std::ostream &operator<<(std::ostream &out, const Person &p) {
return out << p.name << ", " << p.age;
}
孩子是一个人,孩子知道孩子的父母是谁是有道理的。但是,我不确定如何处理这种“知识”。这是我用于子类的代码:
//Header
class Child : public Person
{
private:
const Person *parent;
public:
Child();
Child(std::string name, int age);
Child(std::string name, int age, const Person *parent);
Child(const Child &child, const Person *parent);
Child(const Person &person);
~Child();
Child &operator=(const Child &other);
void print() const;
friend std::ostream &operator<<(std::ostream &out, const Child &c);
};
//cpp
Child::Child() {
std::cout << "Child empty constructor" << std::endl;
}
Child::Child(std::string name, int age) : Person(name, age), parent(nullptr) {
std::cout << "Orphan (" << name << ") constructor" << std::endl;
}
Child::Child(std::string name, int age, const Person *parent) :
Person(name, age), parent(parent) {
std::cout << "Child (" << name << ") default constructor" << std::endl;
}
Child::Child(const Child &child, const Person *parent) :
Person(child.name, child.age), parent(parent) {
std::cout << "Child (" << child.name << ") copy constructor" << std::endl;
}
Child::Child(const Person &person) : Person(person), parent(nullptr) {
std::cout << "Child from person (" << name << ") constructor" << std::endl;
}
Child::~Child() {
std::cout << "Child (" << name << ") destructor" << std::endl;
}
Child & Child::operator=(const Child & other) {
name = other.name;
age = other.age;
parent = other.parent;
std::cout << "Child (" << name << ") assignment constructor" << std::endl;
return *this;
}
void Child::print() const {
if(parent)
std::cout << *this << " is child of " << *parent << std::endl;
else
std::cout << *this << " is orphan" << std::endl;
}
std::ostream &operator<<(std::ostream &out, const Child &c) {
return out << c.name << ", " << c.age << " is " <<
(c.parent ? ("child of " + c.parent->getName() + ", " + std::to_string(c.parent->getAge())) : "orphan");
}
这是我得到的输出:
我想我的问题仍然存在,有人能举例说明它应该被视为优秀的C ++吗?
@ user4581301如果您查看更新后的主页,是否应该返回std::unique_ptr
而不是* (raw pointer)
?在这种情况下,我的功能将如下所示:
std::unique_ptr<Person> makePerson2()
{
string name;
int age;
cout << "Input name: ";
cin >> name;
cout << "Input age: ";
cin >> age;
return std::unique_ptr<Person>(new Person(name, age));
}
变量声明为:
std::unique_ptr<Person> upParent = makePerson2();
cout << "printing: " << *upParent << endl;
这会被认为是比我到目前为止“更好”的C ++吗?
答案 0 :(得分:5)
我认为关于C ++ 最重要的事情之一,特别是如果你来自Java / C#background :
默认情况下,对象是值类型,而不是引用类型!
您可以简单地编写完整的代码:
int main()
{
//this work
Person person("John Doe", 22);
//this work
Child child("Johnny Doe", 2, person);
cout << "---end of main---" << endl;
return 0;
}
看看代码怎么变成什么?您不必担心分配,删除未使用的对象等,因为对象不是开头的引用类型!
我个人的规则层次结构如下:
std::unique_ptr
,例如动态多态。请记住,C ++主要在模板上作为静态多态,而不是Java样式继承+覆盖技术。 std::shared_ptr
,并且只有在您确定有许多所有者时才会使用,例如在不同线程上引用的对象。在极端情况下应使用std::shared_ptr
。始终复制共享指针。永远不要通过引用传递共享指针。无论如何,new
,new[]
,delete
和delete[]
几乎已被弃用。只有图书馆作者才能在非常极端的情况下使用它们。 std::make_
应该是在堆上分配对象的唯一方法,以及std::vector
和std::list
等STL容器。