我在为类定义构造函数时遇到问题,而且我以前定义它们的方式也无法正常工作。
这是针对edx c ++中级课程的。当我尝试定义一个继承自其他类的类时,使用构造函数引用我的基类无法正常工作,因此无法正确定义我的新类。第一个代码中第一次使用构造函数(使用可以正常工作的“:”表示法)和第二个代码中第二个构造函数(定义类似函数,我之前已经正确使用并且在这里不起作用)之间有什么区别?
我有一个名为Person的基类和一个从基类继承的Student类。当我尝试初始化一个调用Person类构造函数之一的Student对象时,它给出错误的答案。我认为这是因为我定义构造函数的方式。我将它们设为函数,并在花括号中初始化变量。我之前使用过这种方法,并且可以正常工作,但是在这里不起作用。但是在花括号前使用“:”的标准方法在这里可以正常工作。我想知道这两者之间有什么区别?
Person.h:
#pragma once
#include <string>
class Person
{
private:
std::string name;
protected:
int age;
public:
Person();
Person(const std::string & name, int age);
void displayNameAge() const;
};
Person.cpp:
#include "pch.h"
#include "Person.h"
#include <iostream>
//Person::Person()
// : name("[unknown name]"), age(0)
//{
// std::cout << "Hello from Person::Person()" << std::endl;
//}
Person::Person()
{
name = "[unknown name]";
age = 0;
std::cout << "Hello from Person::Person()" << std::endl;
}
Person::Person(const std::string & name, int age)
{
this->name = name;
this->age = age;
std::cout << "Hello from Person::Person(string, int)" << std::endl;
}
//Person::Person(const std::string & name, int age)
// : name(name), age(age)
//{
// std::cout << "Hello from Person::Person(string, int)" << std::endl;
//}
void Person::displayNameAge() const
{
std::cout << name << ", " << age << std::endl;
}
Student.h:
#pragma once
#include "Person.h"
class Student : public Person
{
private:
std::string course;
public:
Student();
Student(const std::string & name, int age, const std::string & course);
void displayCourse() const;
};
Student.cpp:
#include "pch.h"
#include "Student.h"
#include <iostream>
Student::Student()
{
course = "[unassigned course]";
std::cout << "Hello from Student::Student()" << std::endl;
}
// first method: the right one
//Student::Student(const std::string & name, int age, const std::string & course)
// : Person(name, age), course(course)
//{
// std::cout << "Hello from Student::Student(string, int, string)" << std::endl;
//}
// second method: the wrong one
Student::Student(const std::string & name, int age, const std::string & course)
{
Person(name, age);
this->course = course;
std::cout << "Hello from Student::Student(string, int, string)" << std::endl;
}
void Student::displayCourse() const
{
std::cout << course << std::endl;
}
Main.cpp:
#include "pch.h"
#include "Student.h"
int main()
{
// Create a Student object using the no-argument constructor.
Student Student1;
Student1.displayNameAge();
Student1.displayCourse();
// Create a Student object using the parameterized constructor.
Student Student2("Jane Smith", 25, "Physics");
Student2.displayNameAge();
Student2.displayCourse();
return 0;
}
预期结果:
Hello from Person::Person()
Hello from Student::Student()
[unknown name], 0
[unassigned course]
Hello from Person::Person(string, int)
Hello from Student::Student(string, int, string)
Jane Smith, 25
Physics
实际结果:
Hello from Person::Person()
Hello from Student::Student()
[unknown name], 0
[unassigned course]
Hello from Person::Person()
Hello from Person::Person(string, int)
Hello from Student::Student(string, int, string)
[unknown name], 0
Physics
答案 0 :(得分:1)
您缺少的是初始化列表。
Type::Type(Parameters)
: member1(init) // This is the initializer list
, member2(init)
{
Your code
}
如果您未明确提供一个,则编译器将使用父类的默认构造函数为您完成此工作,然后为每个成员调用默认构造函数。
所以让我们看看你的课程。
Student::Student(const std::string & name, int age, const std::string & course)
{
// Code
}
那是你写的。但这就是编译器实现的。
Student::Student(const std::string & name, int age, const std::string & course)
: Person()
, course()
{
// Code
}
因此,由于您没有执行任何操作,因此编译器将其调用添加到Person
默认构造函数和course (std::string)
默认构造函数中。
现在,如果您的基类没有默认构造函数,就会出现问题。然后,编译器无法添加适当的调用,并且会生成编译器错误。
但是还有一个问题,就是您编写此方法的效率很低,因为您基本上将所有成员初始化两次。调用默认构造函数,然后在 Code 部分中,使用另一个值重新初始化成员。
Student::Student(const std::string & name, int age, const std::string & course)
: Person(name, age)
, course() // Initialize it to empty here.
{
course = "[unassigned course]"; // Re-Initialize it with info.
}
您只需执行一次:
Student::Student()
: Person() // Note person must have a default constructor for this to work.
, course("[unassigned course]")
{}
Student::Student(const std::string & name, int age, const std::string & course)
{
Person(name, age);
// CODE.
}
这没有按照您的想法做。
让我们添加初始化列表。
Student::Student(const std::string & name, int age, const std::string & course)
: Person()
, course()
{
Person(name, age); // This is creating a person object localy.
// the person object has no name so is a
// temporary variable and goes out of scope
// at the ';'. So it is created and destroyed
// in place before other code is executed.
//
// This does not help initialize the class.
// It is creating a completely different
// and independent object.
// CODE.
}
您可以在此处查看执行情况:
Hello from Person::Person() // Init parent
Hello from Person::Person(string, int) // Init the temp object.
// If you put a print in the destructor
// You will also see that executed
// Before the Student
// This is also why the object has "unknown name" and 0 age.
Hello from Student::Student(string, int, string) // Now we init the student
[unknown name], 0
Physics
是否存在需要初始化对象版本的有效方案?我个人认为不会(如果有的话就忽略它),所以要摆脱Person
和Student
的默认构造函数。这样就无法创建未初始化的Students
或`People。